Streaming in Next.js: How Progressive Rendering Works

Streaming sends HTML to the browser in chunks as each part of a page becomes ready. Learn how Suspense and loading files make it work.

7 min read

Streaming in Next.js means the server sends a page's HTML in chunks as each part becomes ready, instead of waiting for the whole page to render. The browser paints the first chunk immediately, then fills in the rest as it arrives.

This matters when one part of a page is slow. Without streaming, a slow database query delays the entire page. With streaming, the fast parts reach the browser first while the slow part shows a fallback until its data is ready.

How Next.js streams

Next.js streams through React Suspense. When a component suspends, React renders its fallback and sends it in the initial chunk, then keeps rendering the rest.

When the slow work finishes, its finished HTML arrives in a later chunk and swaps into place. The fallback itself is real markup in the very first response, not something a client script adds afterwards.

There are two ways to create these boundaries: a loading file at the route level, and a Suspense boundary around a specific component. Both rely on the same React behavior.

App.tsxApp.tsx
// app/dashboard/page.tsx
import { Suspense } from "react";
import { PostFeed, Weather } from "./components";
 
export default function Dashboard() {
  return (
    <section>
      <Suspense fallback={<p>Loading feed</p>}><PostFeed /></Suspense>
      <Suspense fallback={<p>Loading weather</p>}><Weather /></Suspense>
    </section>
  );
}

PostFeed and Weather are async components that each fetch their own data. Each Suspense boundary streams independently: the dashboard shell renders at once, then the feed and weather fill in as each finishes. If weather is slow, the feed still appears first.

Blocking rendering vs streaming

In blocking rendering, the server waits for every fetch before sending a single byte, and the browser shows nothing until then. Streaming replaces that one long wait with many smaller waits, one per boundary. The total work is the same, but the time before the first paint is not.

Blocking renderStreaming
First byteAfter the slowest fetchAfter the shell renders
What arrives firstNothingShell and fallbacks
One slow queryDelays the whole pageDelays only its boundary

What the browser sees

On a slow connection, the user sees the shell and fallbacks first, then the resolved sections replace them. The order in which sections appear depends on how fast each one resolves, not on their order in the source.

Each boundary is also a hydration unit. React hydrates the streamed sections independently and prioritizes whatever the user interacts with, instead of hydrating the whole page in one blocking pass.

Crawlers are handled differently. Next.js detects HTML-limited bots by user agent and waits for the full render, sending one finished document rather than a shell with fallbacks, so those bots never index a skeleton.

Boundaries add a small amount of coordination overhead, so wrap only the genuinely slow pieces. Splitting every component into its own boundary makes the page flicker without a real speed win.

For the route-level fallback, see loading.js and instant loading states, and for controlling each boundary see Suspense boundaries.

Streaming requires a server runtime that supports it, so it is not available with a static export. It also depends on what sits in front of that server: a reverse proxy, CDN, or compression layer that buffers the response can collect every chunk before forwarding it, which hides the benefit even though the server streamed correctly.

Rune AI

Rune AI

Key Insights

  • Streaming sends HTML in chunks instead of one complete response.
  • The browser paints the first chunk, then fills in the rest.
  • Suspense boundaries and loading files create the chunk boundaries.
  • Slow work shows a fallback while the rest of the page renders.
  • Streaming needs a server runtime and does not work with static export.
RunePowered by Rune AI

Frequently Asked Questions

Does streaming require a special server?

It requires a server runtime that supports streaming, such as Node.js. It is not available with a static export.

What is the difference between streaming and server-side rendering?

Server-side rendering produces one complete HTML response. Streaming sends that HTML in chunks as each part becomes ready.

Do I need to enable streaming?

No. It happens automatically when you add a loading file or a Suspense boundary around async work.

Conclusion

Streaming sends HTML in chunks as each part of a page becomes ready. Suspense boundaries and loading files are what split the page into those chunks, so slow work no longer blocks the whole route.