← Docs

Suspense Patterns

Recipes for streaming, skeletons, and partial hydration in Next.js App Router.

Streaming a server component

// app/dashboard/page.tsx
import { Suspense } from "react";
import { StatsCard } from "./stats-card";

export default function Dashboard() {
  return (
    <Suspense fallback={<StatsSkeleton />}>
      <StatsCard />
    </Suspense>
  );
}

The fallback renders instantly. The server streams StatsCard once its async work finishes.

Parallel data with independent boundaries

<Suspense fallback={<Skeleton />}>
  <UserProfile />
</Suspense>
<Suspense fallback={<Skeleton />}>
  <RecentOrders />
</Suspense>

Each boundary resolves independently — no waterfall. The page paints progressively.

Nested suspense for priority loading

<Suspense fallback={<Shell />}>
  <PageContent />
  <Suspense fallback={<CommentsSkeleton />}>
    <Comments />
  </Suspense>
</Suspense>

The outer shell waits for critical content. Comments load lazily inside the already-painted layout.

Skeleton component

function StatsSkeleton() {
  return (
    <div className="animate-pulse space-y-3">
      <div className="h-4 w-2/3 rounded bg-white/10" />
      <div className="h-8 w-1/3 rounded bg-white/10" />
    </div>
  );
}

Tailwind animate-pulse plus translucent backgrounds give instant perceived performance.