100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
JavaScript

Streaming and Suspense

Learn how Next.js streams HTML from the server using React Suspense so pages can show content progressively instead of waiting on the slowest data fetch.

Rendering ModelsAdvanced10 min readJul 10, 2026
Analogies

Why Streaming Matters

Without streaming, a Server Component page must finish every single data fetch before the server can send any HTML at all -- if one section depends on a slow API call, the entire page waits, even if other sections were ready instantly. Streaming lets the server send an initial HTML shell immediately and then push additional HTML chunks over the same connection as slower parts of the tree finish rendering, using HTTP's chunked transfer encoding under the hood. React's Suspense boundaries mark exactly which parts of the tree are allowed to 'not be ready yet' without blocking everything else.

🏏

Cricket analogy: It's like a stadium opening the gates and letting fans take their seats immediately, instead of making everyone wait outside until the groundstaff finishes preparing every single food stall before anyone can enter.

Using Suspense Boundaries

In the App Router, wrapping a slow async Server Component in a <Suspense> boundary with a fallback prop tells React to render that fallback (like a skeleton loader) immediately, then swap in the real content once the wrapped component's data resolves -- without blocking the rest of the page. Next.js also generates an automatic loading.tsx file per route segment, which Next.js wraps around the page content in an implicit Suspense boundary, giving instant route-level loading UI without manually adding Suspense everywhere.

🏏

Cricket analogy: It's like a broadcaster cutting to a 'DRS review in progress' graphic (fallback) while the actual ball-tracking replay is still being processed, then swapping in the real footage the instant it's ready.

tsx
// app/dashboard/page.tsx
import { Suspense } from 'react';

async function RevenueChart() {
  const data = await fetch('https://api.example.com/revenue', { cache: 'no-store' }).then((r) => r.json());
  return <Chart data={data} />; // slow, third-party analytics query
}

async function RecentOrders() {
  const orders = await fetch('https://api.example.com/orders', { cache: 'no-store' }).then((r) => r.json());
  return <OrdersTable orders={orders} />; // fast, indexed database query
}

export default function DashboardPage() {
  return (
    <div>
      {/* Renders immediately, no waiting */}
      <Suspense fallback={<OrdersSkeleton />}>
        <RecentOrders />
      </Suspense>

      {/* Streams in later once the slow analytics query resolves */}
      <Suspense fallback={<ChartSkeleton />}>
        <RevenueChart />
      </Suspense>
    </div>
  );
}

Because Suspense boundaries are independent, RecentOrders and RevenueChart in the example above stream in whenever each is individually ready -- if RecentOrders resolves first, its skeleton is replaced immediately, without waiting for the slower RevenueChart.

Streaming, SEO, and loading.tsx

Search engine crawlers that execute JavaScript generally wait for the full response before indexing, so streaming's progressive HTML delivery doesn't hurt SEO the way client-side-only loading spinners would -- crawlers still eventually receive complete content within the same response. A route's loading.tsx file is automatically used as the Suspense fallback for the entire page.tsx in that segment while any of its data is still resolving, and Next.js also enables instant navigation feedback: clicking a link to a route with a loading.tsx shows that fallback right away, even before the destination page's data fetches start resolving.

🏏

Cricket analogy: It's like a match report journalist waiting for the full scorecard to finish transmitting before filing the story, so a delayed final over doesn't cause an incomplete report to be published permanently.

Streaming requires an environment that supports it end to end. Some edge caches, proxies, or older CDN configurations buffer the entire response before forwarding it, which cancels out the perceived benefit of streaming; verify your hosting setup actually forwards chunked responses progressively.

  • Streaming lets the server send an HTML shell immediately and push in additional chunks as slower parts of the tree resolve.
  • React <Suspense> boundaries mark which parts of the tree can show a fallback without blocking the rest of the page.
  • Independent Suspense boundaries resolve and swap in on their own schedule, not in a fixed order.
  • loading.tsx automatically wraps a route segment's page.tsx in an implicit Suspense boundary.
  • loading.tsx also provides instant navigation feedback the moment a link is clicked.
  • JS-executing crawlers generally wait for the complete streamed response, so streaming doesn't harm SEO the way client-only spinners can.
  • Streaming benefits require the hosting/CDN layer to forward chunked responses without fully buffering them first.

Practice what you learned

Was this page helpful?

Topics covered

#JavaScript#NextJsStudyNotes#WebDevelopment#StreamingAndSuspense#Streaming#Suspense#Matters#Boundaries#StudyNotes#SkillVeris