← Back to blog

Suspense and Streaming

Suspense specifies loading UI while async content loads, enabling streaming in Next.js.

Example: Dashboard

From app/dashboard/page.tsx:

export default function DashboardPage({ searchParams }) { return ( <div> <Suspense fallback={<PostTabsSkeleton />}> <PostTabs /> </Suspense> <Suspense fallback={<PostListSkeleton />}> <PostList searchParams={searchParams} /> </Suspense> </div> ); }

Separate boundaries let each section stream independently.

Co-locating Skeletons

From app/dashboard/_components/PostList.tsx:

export async function PostList({ searchParams }) { const posts = await getPosts(filter); return posts.map(post => <Card key={post.slug}>...</Card>); } export function PostListSkeleton() { return ( <div className="space-y-4"> {[1, 2, 3].map(i => ( <Card key={i}> <Skeleton className="h-6 w-48" /> <Skeleton className="h-4 w-24" /> </Card> ))} </div> ); }

Export skeletons alongside their components to keep them in sync.

March 5, 2026119 words