My API Responded in 4 ms, but Navigation Still Felt Slow
I was debugging a project management app built with SvelteKit and a Rust API.
On my local machine, everything felt instant. On the VPS, navigation felt heavy. Opening pages like Tickets or Timeline took too long. Clicking a ticket caused a noticeable delay before the preview appeared.
I thought the problem was the server. I suspected slow database queries or a weak VPS.
The measurements proved me wrong.
I checked the feature list endpoint. For only 52 tickets, the API responded in 4 ms. That sounds fast. But the response size was 354 KB.
The SvelteKit route payload showed the same issue. The data size was huge for a simple list.
The problem was not speed. The problem was weight.
The descriptions alone made up 80% of the total response. The list endpoint was returning full Markdown descriptions for every single item.
This is a common trap. The list endpoint had become a detail endpoint. Every time a page needed a list, it paid the price for data it did not use.
The UI usage does not determine the payload. The loader return shape does.
If your loader returns a full object, SvelteKit serializes that entire object into the route data. Even if you never render a field, it still travels across the network.
I fixed this by separating summary data from detail data.
I created two different contracts:
• A list contract for summaries (ID, title, status, dates). • A detail contract for full information (descriptions, commands).
I split the API into two endpoints:
- GET /features (returns summaries)
- GET /features/:id (returns one full detail)
I also changed how the frontend works. Now, the app renders the list immediately using summary data. When you click a ticket, the app shows a shell and fetches the heavy detail data in the background.
The results were massive:
• Feature list API: 89.6% reduction • Tickets route data: 91.4% reduction • OpenSpec docs API: 98.9% reduction
The database was always fast. The real bottleneck was the data contract between the API and the page.
Lessons for list-heavy apps:
- Measure response size, not just response time.
- Treat list and detail payloads as separate things.
- Never return large text fields in a list view.
- Check what your SSR loader is actually serializing.
- Lazy-load detail data but show the UI shell immediately.
- Do not use a loading spinner to hide a heavy payload.
A fast query does not guarantee a fast page.
Source: https://dev.to/ahikmah/my-api-responded-in-4-ms-but-navigation-still-felt-slow-1hk8