Here is the shape of almost every "Next.js is slow" complaint I get asked to look at: the page has five sections. Four render in milliseconds. One runs a heavy query, a recommendations block, a dashboard widget, an unpaged comment count, and because the whole page waits for its slowest part, users stare at nothing for 1.5 seconds.
The fix has shipped in React for years now and most codebases still do not use it. Wrap the slow section in Suspense. Let the fast part ship. Let the slow part stream.
The three-line change that halves perceived load
Move the slow fetch into an async server component that awaits its own data. Wrap the component in a Suspense boundary with a skeleton fallback. Done: the parent no longer awaits the child, the shell renders and ships immediately, and the slow section streams into its reserved slot when the query resolves.
No caching layer to configure. No client fetching library. No loading state management. The pattern is server-side end to end, and the JavaScript bundle never grows.
The skeleton is part of the design
A fallback that collapses to 40 pixels when the real section needs 400 makes the whole page jump on arrival, and users read layout shift as broken. The skeleton should reserve the section's real height and roughly mirror its layout. This is a design task, not a developer afterthought, and it is the difference between streaming that feels instant and streaming that feels glitchy.
Where the boundaries go
Per slow section, not per route. The App Router's loading.js wraps the whole segment in one boundary, which helps, but it means your header and hero still wait for the slowest widget in the page. A boundary around each independent slow section lets everything else render at full speed. On a dashboard page that is typically three or four boundaries, each with a skeleton sized to its content.
What this does not fix
Streaming is a rendering-order pattern, not a database fix. A query taking four seconds still takes four seconds; the difference is who waits for it. If the slow section is the main content, above the fold, there is nothing to show first, and the honest fixes are caching, indexes, or smaller queries. Suspense buys perceived performance for pages with a fast shell and slow satellites. Most real pages are exactly that shape.
If your page feels slow and you cannot name the section responsible, profile it first. Then give that one section a boundary instead of making every user wait for it.