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.