Loading & streaming in Next.js
From the Next.js cheat sheet · Data Fetching · verified Jul 2026
Loading & streaming
typescript
// app/products/loading.tsx
export default function Loading() {
return (
<div className="animate-pulse">
<div className="h-8 bg-gray-200 rounded w-1/4 mb-4"></div>
<div className="grid grid-cols-3 gap-4">
{[...Array(6)].map((_, i) => (
<div key={i} className="h-40 bg-gray-200 rounded"></div>
))}
</div>
</div>
)
}
// Using Suspense for parts of the page
import { Suspense } from 'react'
export default function ProductPage() {
return (
<div>
<h1>Products</h1>
<Suspense fallback={<div>Loading products...</div>}>
<ProductList /> {/* Async Server Component */}
</Suspense>
<Suspense fallback={<div>Loading reviews...</div>}>
<Reviews /> {/* Another async component */}
</Suspense>
</div>
)
}
// Streaming with generateMetadata
export async function generateMetadata(
{ params }: { params: Promise<{ id: string }> }
) {
// This runs in parallel with the page
const { id } = await params
const product = await getProduct(id)
return {
title: product.name,
description: product.description,
}
}
// Progressive enhancement with loading boundaries
export default function Layout({ children }: { children: React.ReactNode }) {
return (
<div>
<nav>Static Navigation</nav>
<Suspense fallback={<SidebarSkeleton />}>
<Sidebar /> {/* Async component */}
</Suspense>
<main>
<Suspense fallback={<ContentSkeleton />}>
{children}
</Suspense>
</main>
</div>
)
}💡 loading.tsx shows while data loads
⚡ Suspense for granular loading states
📌 Streaming allows progressive rendering
🟢 Skeleton UI improves perceived performance