Skip to content

Streaming in Next.js

Streaming lets Next.js send a page's HTML to the browser in pieces, as each piece becomes ready, instead of waiting for every single data source to resolve before sending anything. This lesson explains how it works and how to use it deliberately.

Sending HTML Progressively, Not All at Once

Without streaming, a dynamically-rendered page must wait for every Server Component's data to resolve before the server sends any HTML at all — one slow data source blocks the entire response. Streaming, powered by React <Suspense>, lets Next.js send the parts of the page that are ready immediately, then stream in additional HTML (plus a small script to slot it into place) as slower parts finish.

loading.tsx (covered earlier) is actually a specific application of streaming — Next.js wraps the whole page's page.tsx in a <Suspense> boundary automatically. This lesson focuses on adding your own, more granular <Suspense> boundaries around individual components.

import { Suspense } from "react";

export default function DashboardPage() {
  return (
    <>
      <h1>Dashboard</h1>             {/* renders immediately */}
      <Suspense fallback={<p>Loading revenue...</p>}>
        <RevenueChart />              {/* streams in once ready */}
      </Suspense>
      <Suspense fallback={<p>Loading orders...</p>}>
        <RecentOrders />              {/* streams in independently */}
      </Suspense>
    </>
  );
}

The heading appears instantly; RevenueChart and RecentOrders each stream in independently, whichever finishes first.

Suspense Boundary Syntax

<Suspense fallback={<LoadingSkeleton />}>
  <SlowAsyncComponent />
</Suspense>
  • Any async Server Component wrapped in <Suspense> can suspend the boundary while it loads.
  • The fallback prop is shown instantly, then swapped for the real content once ready.
  • Multiple <Suspense> boundaries on the same page stream independently of each other.
  • Streaming requires a dynamic (or partially dynamic) response — fully static pages have nothing to stream.

Streaming Cheat Sheet

Where streaming applies automatically vs. manually.

Mechanism Scope
loading.tsx Automatic Suspense boundary for an entire route
Manual <Suspense> Granular boundary around one specific component
Multiple <Suspense> boundaries Each streams independently, in any order they resolve
Underlying mechanism React Server Components + Suspense + HTTP streaming

Why Streaming Improves Perceived Performance

Streaming doesn't necessarily make the total time-to-fully-loaded any faster — the slow data source still takes just as long. What it improves is perceived performance: users see meaningful content (navigation, headings, fast sections) immediately, rather than staring at a blank page while everything loads together.

Choosing Where to Add Suspense Boundaries

A good rule of thumb is to wrap exactly the components whose data sources are meaningfully slower than the rest of the page — wrapping every single component individually adds unnecessary complexity without a proportional UX benefit.

  • Wrap slow, non-critical widgets (charts, recommendations, comment counts).
  • Don't wrap fast, critical content that should always render together with the page shell.
  • Group related, similarly-fast content under a single shared boundary instead of many tiny ones.

Common Mistakes

  • Wrapping every individual component in its own <Suspense> boundary, fragmenting the UI unnecessarily.
  • Expecting streaming to reduce the actual time a slow API call takes, rather than just its perceived impact.
  • Forgetting that streaming requires dynamic (or partially dynamic) rendering — fully static routes don't stream.
  • Not designing a fallback that visually resembles the real content, causing jarring layout shifts when it swaps in.

Key Takeaways

  • Streaming sends a page's HTML progressively, as each part becomes ready, instead of all at once.
  • React <Suspense> boundaries define which parts of the page can stream independently.
  • loading.tsx is an automatic, whole-route application of the same underlying mechanism.
  • Streaming improves perceived performance even when total load time is unchanged.
  • Add Suspense boundaries deliberately around genuinely slow sections, not everywhere.

Pro Tip

Design fallback skeletons that match the real content's approximate size and layout — a fallback that's a different height than the actual content causes a visible layout shift the moment the real content streams in, which undermines the smooth feel streaming is supposed to provide.