React Suspense & Streaming: A Complete Guide - By Sourav Mishra (@souravvmishra)
Unlock better user experience with React Suspense and Streaming in Next.js. Learn how to implement loading states and optimize server-side rendering.
In this guide, I, Sourav Mishra, break down how React Suspense and Streaming transform the way we build performant web applications.
Traditional Server-Side Rendering (SSR) has a blocking problem: the user sees nothing until the entire page is ready. React Suspense solves this by allowing parts of the UI to "stream" in as soon as they are ready.
Why Suspense Matters?
- Instant Feedback: Show a skeleton or loading spinner immediately.
- Selective Hydration: Interactive parts of the page become usable faster.
- Better SEO: Search engines can index the content as it streams in.
1. The Basics: Using <Suspense>
The core concept is wrapping a slow component in a <Suspense> boundary.
// components/Dashboard.tsx
import { Suspense } from "react";
import { RevenueChart } from "./RevenueChart";
import { LatestInvoices } from "./LatestInvoices";
import { CardSkeleton } from "./Skeletons";
export default function Dashboard() {
return (
<div className="grid gap-6">
<Suspense fallback={<CardSkeleton />}>
<RevenueChart />
</Suspense>
<Suspense fallback={<CardSkeleton />}>
<LatestInvoices />
</Suspense>
</div>
);
}
In this example, RevenueChart and LatestInvoices can fetch their own data independently. If RevenueChart takes 2 seconds and LatestInvoices takes 0.5 seconds, the user sees invoices first—they don't wait for the slowest component.
2. Streaming with loading.tsx
In Next.js App Router, this pattern is built-in. Adding a loading.tsx file to a route segment automatically wraps the page content in a Suspense boundary.
app/
dashboard/
layout.tsx
page.tsx <-- The slow content
loading.tsx <-- The fallback UI
loading.tsx:
export default function Loading() {
return <div className="animate-pulse bg-gray-200 h-96 rounded-lg" />;
}
This is "instant loading states" at the route level.
3. Data Fetching in Server Components
To make streaming work, you need to fetch data inside the component awaiting the data.
// components/RevenueChart.tsx
async function getRevenue() {
// Simulate slow db call
await new Promise((resolve) => setTimeout(resolve, 3000));
return "$50,000";
}
export async function RevenueChart() {
const revenue = await getRevenue();
return (
<div className="p-6 bg-white shadow rounded">
<h3 className="text-gray-500">Total Revenue</h3>
<p className="text-2xl font-bold">{revenue}</p>
</div>
);
}
Because RevenueChart is an async component, Next.js knows to pause rendering at this component, stream the HTML up to this point, send the fallback from the parent Suspense, and then swap in the real content when await getRevenue() resolves.
4. Best Practices
- Wrap Granularly: Don't wrap the whole page in one Suspense if components are independent. Wrap them individually so fast parts load fast.
- Use Skeletons: Avoid generic spinners. Use UI skeletons that mimic the final layout to reduce Cumulative Layout Shift (CLS).
- Handle Errors: Pair
<Suspense>with<ErrorBoundary>(orerror.tsxin Next.js) so a failed fetch doesn't crash the entire page.
See my guide on Why Server Actions to see how data mutation pairs with this data fetching model.
Conclusion
Streaming is a game-changer for perceived performance. It stops the "white screen of death" and makes your application feel responsive, even on slower networks.
For more styling tips to build those skeleton loaders, check out my Class Variance Authority guide.
FAQ
Q: Does Suspense work with Client Components?
Yes, Suspense works on the client too, typically for code-splitting (lazy loading components) or data fetching with libraries like use or TanStack Query.
Q: Will this hurt my SEO? No. Search crawlers wait for the stream to finish. They utilize the final HTML content.
Q: Can I nest Suspense boundaries? Absolutely. You can have a global loading state for the main layout and finer-grained loading states for widgets inside the page.
This guide was written by Sourav Mishra, an expert in React performance and Next.js architecture.