Suspense & Streaming

In standard Server-Side Rendering (SSR), the server must fetch all the data before it can begin sending the HTML response. If you have a slow database query that takes 3 seconds, your user stares at a blank white screen for 3 entire seconds. Next.js fixes this completely using Streaming via React <Suspense>.

How Streaming Works

Streaming allows you to break down the HTML document into smaller "chunks". The static parts of your UI (like the Navbar and Sidebar) are sent to the user instantly. The slower, data-dependent parts of the UI are wrapped in <Suspense>. Next.js instantly sends a "Loading placeholder" (like a spinner or skeleton) in their place, and streams the real data in later once it resolves.

Using React Suspense

You can manually implement streaming by wrapping a slow Server Component in a Suspense boundary.

import { Suspense } from 'react';
import { SlowProductList } from './SlowProductList'; 
import { FastSidebar } from './FastSidebar';

export default function Dashboard() {
  return (
    <div className="grid">
      {/* Renders instantly */}
      <FastSidebar />

      <main>
        {/* Renders a localized loading spinner instantly, then streams the products! */}
        <Suspense fallback={<p>Loading products...</p>}>
          <SlowProductList />
        </Suspense>
      </main>
    </div>
  );
}

The `loading.js` Convention

Next.js App router provides a special file convention called loading.js. If you create this file inside a folder, Next.js automatically wraps the page.js inside that folder in a Suspense boundary using your loading.js as the fallback!

// app/dashboard/loading.js

export default function Loading() {
  // This UI will instantly show while page.js data is fetching
  return <div className="skeleton-loader">Loading Dashboard...</div>
}

Why is this revolutionary?

Because of Streaming, Time To First Byte (TTFB) is virtually zero even for complex, highly dynamic pages. Users can begin interacting with your Navbar and menus while the main content fetches seamlessly in the background. Next, let's explore how to optimize those data fetches using Caching & Revalidation.