Next.js Loading UI and Streaming explains how to display skeleton states immediately while backend data fetches load in the background.
Next.js automatically wraps route segments in React Suspense boundaries whenever a loading.tsx file is placed inside a route folder.
flowchart TD
A["User Navigates to Route"] --> B["Next.js Sends Immediate Skeleton UI"]
B --> C["Server Streams HTML Data Chunks"]
C --> D["Hydrated Full Page Content Rendered"]
loading.tsx)Place loading.tsx in any route folder to show an immediate placeholder component while page.tsx executes server async data fetching:
// app/dashboard/loading.tsx
export default function DashboardLoading() {
return (
<div className="p-6 space-y-4 animate-pulse">
<div className="h-8 bg-gray-300 rounded w-1/4"></div>
<div className="h-32 bg-gray-200 rounded"></div>
<div className="h-32 bg-gray-200 rounded"></div>
</div>
);
}
Instead of delaying an entire page load for slow API queries, wrap specific slow components in explicit React <Suspense> boundaries:
// app/dashboard/page.tsx
import { Suspense } from 'react';
import FastWidget from '@/components/FastWidget';
import SlowAnalyticsWidget from '@/components/SlowAnalyticsWidget';
import WidgetSkeleton from '@/components/WidgetSkeleton';
export default function DashboardPage() {
return (
<div className="space-y-6">
<h1 className="text-2xl font-bold">Dashboard</h1>
{/* Renders immediately */}
<FastWidget />
{/* Streams in when ready */}
<Suspense fallback={<WidgetSkeleton />}>
<SlowAnalyticsWidget />
</Suspense>
</div>
);
}
Streaming with React Suspense replaces full-page spinner delays with instant layout feedback. Users receive content faster, improving retention and user experience.
Sign in to track your learning journey, earn industry-recognized certificates, and join our elite developer community.
Quick Access With