Streaming SSR with Suspense in Next.js 15
Learn how to leverage the App Router and React Suspense to stream server-rendered content incrementally in Next.js 15.
Next.js 15 builds on top of React’s Suspense to offer streaming server-side rendering (SSR). Instead of waiting for the entire page to load before sending any HTML, you can stream partial responses to the client in chunks, enhancing perceived performance. This tutorial walks you through creating a streaming SSR flow using the App Router and a few carefully placed Suspense boundaries.
1. Project Setup
Create a new Next.js 15 application with TypeScript, the App Router, and a dedicated src
directory:
This yields a structure like:
Run a quick test:
Visit http://localhost:3000 to confirm it’s up and running.
2. Understanding Streaming SSR and Suspense
- Streaming SSR: Instead of collecting all data and rendering everything at once, Next.js can send partial responses as soon as each piece of content is ready.
- React Suspense: Allows you to delay rendering part of a component tree until its data or resource is loaded, showing a fallback (like a spinner) in the meantime.
- App Router: In Next.js 15, server components plus the Web Streams API make partial HTML streaming simpler behind the scenes—no extra config required.
3. Creating a Slow Server Component
Let’s create a server component in app/
that simulates a delayed data fetch. Next.js 15’s default is to treat files in app/
as server components, so we just ensure not to add "use client"
at the top.
Create a folder src/app/slow-data/
(or name it something else you like), and inside a file named SlowData.tsx
:
- Note: We used an
async
function with a manualsetTimeout
to mimic a 4-second delay. This represents a potentially slow external API call.
4. Using Suspense in the Page
Now let’s suspend while waiting for SlowData
. In Next.js 15, you can import this server component into your page (which is also a server component by default) and wrap it in a React Suspense boundary to enable partial streaming.
Open src/app/page.tsx
:
Why It Works
- Suspense boundary: The
<Suspense fallback={<LoadingPlaceholder />}>
lets Next.js send the initial HTML (the page title, etc.) immediately, while deferring theSlowData
content. - Server Streams: When
SlowData
finishes, the server flushes the completed HTML chunk down the wire, updating the client’s page without a full reload.
5. Observing Streaming
- Start the dev server:
- Open http://localhost:3000.
- Notice that the main content (title, paragraph) appears instantly, but the section labeled “Slow Data Component” arrives about 4 seconds later.
- Network Tab: In DevTools, you can see partial HTML chunks streaming. The initial HTML is served, followed by an additional chunk once the
SlowData
has finished loading.
Tip: In some local dev environments, chunk boundaries might be less obvious, but you can still see partial updates or logs confirming incremental responses.
6. Multiple Suspense Boundaries
To illustrate streaming further, you could add another slow server component—somewhere else on the page with a separate <Suspense>
boundary. Each component will load asynchronously, sending incremental chunks as soon as each is ready. For example:
Now both pieces of data stream to the client independently—whichever finishes first gets rendered first.
7. Handling Real Data Fetching
Instead of simulating a timeout, you’d typically make async fetch calls to an API or database from your server component:
If this fetch is slow, placing it under a <Suspense>
boundary in your page ensures incremental streaming.
8. FAQ and Common Pitfalls
-
Do I Need
use client
?- No. Server components (like
SlowData
) should not use"use client"
. Only your page or layout file needs"use client"
if it specifically requires client-side React features. In this tutorial, the page remains a server component, and that’s fine.
- No. Server components (like
-
Can I Combine Suspense with Client Components?
- Yes. If you import a client component that fetches data on the client side, you can still use Suspense for partial hydration. But for streaming SSR to shine, the data fetch typically happens in a server component.
-
What About Production vs. Dev?
- Streaming SSR works in both, but the Dev environment may sometimes batch partial updates differently. You’ll see the best demonstration of streaming in production or by analyzing network requests in both modes.
-
SEO Considerations?
- Streaming SSR doesn’t harm SEO. Crawlers that can parse HTML as it arrives will eventually receive the full content. The partial or incremental nature is primarily about user experience and perceived performance.
9. Conclusion
Streaming SSR with React Suspense in Next.js 15 allows you to:
- Send partial HTML as soon as each server component is ready, reducing perceived load times.
- Decouple components with their own data fetches, each covered by
<Suspense>
boundaries. - Provide meaningful fallbacks (loading spinners or placeholders) for slow components without blocking the rest of the page.
Key Takeaways:
- Server Components + Suspense: The core recipe for streaming SSR in Next.js 15.
- No Extra Config: Next.js handles streaming behind the scenes once you use Suspense boundaries in server components.
- Real-World Usage: Perfect for pages where large data sets, slow external APIs, or complex server logic might otherwise block the entire page from rendering.
Now you’re equipped to deliver incrementally streamed experiences in your Next.js 15 applications, elevating performance and user satisfaction. Experiment with multiple slow or real fetch calls to see streaming SSR’s benefits in action.
Damian Hodgkiss
Senior Staff Engineer at Sumo Group, leading development of AppSumo marketplace. Technical solopreneur with 25+ years of experience building SaaS products.