0PricingLogin
Next.js 15 Fullstack (App Router + Server Actions) · Lesson

Suspense Boundaries and Component-Level Streaming

Wrap slow data components in Suspense to stream them independently from the static shell.

Why Stream at the Component Level?

In the App Router, a page can contain both fast static content (header, nav, layout shell) and slow data-dependent content (a dashboard widget that hits a third-party API).

Without streaming, the whole page waits for the slowest fetch before anything renders. That hurts perceived performance.

Component-level streaming lets Next.js send the static shell immediately, then stream each slow part in as its data resolves. The tool that enables this is React's <Suspense> boundary.

The Blocking Problem

Here a single async Server Component awaits a slow query. Because the page awaits before returning JSX, the user sees nothing until the 2-second fetch finishes.

The fast parts of the page (title, layout) are held hostage by the slow part.

// app/dashboard/page.tsx
async function getStats() {
  // simulates a slow 2s upstream call
  await new Promise((r) => setTimeout(r, 2000));
  return { revenue: 4200, orders: 87 };
}

export default async function DashboardPage() {
  const stats = await getStats(); // blocks the WHOLE page
  return (
    <main>
      <h1>Dashboard</h1>
      <p>Revenue: {stats.revenue}</p>
      <p>Orders: {stats.orders}</p>
    </main>
  );
}

All lessons in this course

  1. Suspense Boundaries and Component-Level Streaming
  2. Crafting Meaningful loading.tsx and Skeletons
  3. Partial Prerendering: Static Shell, Dynamic Holes
  4. Streaming Pitfalls: Layout Shift and Waterfalls
← Back to Next.js 15 Fullstack (App Router + Server Actions)