Streaming SSR in Next.js 13+ allows the server to send HTML in chunks as components render, with Suspense defining loading boundaries and enabling progressive rendering without blocking the initial page load
Streaming SSR represents a fundamental shift in how Next.js renders pages. Traditional Server-Side Rendering (SSR) blocks the response until all data is fetched and all components are rendered on the server, creating a 'all or nothing' waterfall where users stare at a blank screen until everything is ready . Streaming SSR, introduced in Next.js 13 with the App Router and React 18, breaks this paradigm by allowing the server to send HTML to the browser progressively—as soon as any part of the page is ready, it streams immediately . This means users see content almost instantly, while slower components load in the background and stream in when complete. The technical foundation is React 18's renderToPipeableStream API (replacing the synchronous renderToString), combined with Suspense boundaries that mark where streaming can occur .
Chunked transfer encoding: The server uses HTTP/1.1's Transfer-Encoding: chunked (or HTTP/2 streaming) to send HTML in multiple chunks over time, rather than one large response .
renderToPipeableStream: React 18 replaces the synchronous renderToString with this streaming API, allowing the server to start sending HTML immediately while continuing to render .
Suspense boundaries: Components wrapped in Suspense become streaming boundaries—their fallback UI is sent immediately, and the real content streams later when data resolves .
Selective hydration: After streaming to the client, React hydrates components selectively—prioritizing visible and interactive parts first, and hydrating streamed components as they arrive .
RSC Payload integration: In Next.js, streaming also delivers the RSC Payload (binary component tree representation) alongside HTML, enabling seamless client-side navigation without full page reloads .
Suspense is the cornerstone of streaming SSR in Next.js 13+. It serves multiple critical functions: First, it defines streaming boundaries—components wrapped in Suspense become independent rendering units that can stream separately. Second, it provides fallback UI (spinners, skeletons) that renders immediately while the real component loads . Third, and most importantly, Suspense enables non-blocking rendering—the server can send the fallback and continue rendering the rest of the page, unblocking the critical path . Without Suspense, Next.js would have to wait for every component to finish before sending anything. With Suspense, you get progressive enhancement automatically: the browser displays the fallback immediately, and when the async component resolves, React seamlessly replaces it with the final content .
Time-to-First-Byte (TTFB) improvement: The browser starts receiving HTML immediately, often in under 100ms, even if total page render takes seconds .
First Contentful Paint (FCP) optimization: Users see something—headers, navigation, skeletons—instantly, eliminating the dreaded white screen .
Complex page hierarchies: Pages with multiple data dependencies (dashboards, e-commerce, social feeds) benefit most, as slow components don't block fast ones .
Skeleton screens: Using Suspense fallbacks, you can show skeleton loaders that match the final layout, minimizing Cumulative Layout Shift (CLS) .
CDN and edge compatibility: Streaming works through CDNs that support chunked encoding, enabling global distribution of progressive rendering .
Streaming SSR doesn't work in isolation—it integrates deeply with Next.js's App Router ecosystem. The loading.tsx file automatically creates a Suspense boundary for the entire route segment, providing a quick way to add streaming without manual Suspense imports . Server Components stream naturally because they're async by default—when you await a fetch inside a Server Component, that component becomes a streaming boundary . The RSC Payload streams alongside HTML, enabling client-side navigation to also benefit from progressive loading. Even error handling integrates: error.tsx files work within Suspense boundaries, allowing granular error recovery for streamed components .
Client Components limitation: Only Server Components stream naturally. Client Components inside Suspense boundaries still require JavaScript to hydrate before becoming interactive, though their HTML shell streams .
Over-segmentation risk: Too many Suspense boundaries can create a fragmented, jumpy user experience. Group related content thoughtfully .
SEO considerations: Critical content for search engines should not be behind Suspense boundaries without careful fallback design, as some crawlers may not wait for streaming completion .
Caching complexity: Streaming responses are harder to cache at the CDN level than complete HTML pages, requiring more sophisticated caching strategies .
Browser compatibility: While modern browsers support chunked responses, very old browsers may not handle streaming correctly (graceful degradation to full response is automatic but may be slower) .