- React
- Server-Side Rendering, Hydration, and Server Components
- Streaming SSR with Suspense & Selective Hydration
Streaming SSR with Suspense & Selective Hydration
React 18 Streaming SSR uses renderToPipeableStream and Suspense boundaries to break HTML generation into streams, flushing shells immediately while slow queries stream in later. Selective Hydration begins hydrating ready components before all HTML or scripts finish downloading.
Key Learning Objectives
Explain how renderToPipeableStream flushes early HTML shells before slow database queries resolve.
Structure Suspense boundaries to stream independent UI blocks concurrently without blocking the page.
Explain how Selective Hydration hydrates ready components early and prioritizes user click interactions.
Analyze the waterfall reduction achieved by streaming vs traditional blocking SSR.
The Interview Problem & Context
Explain how React 18 breaks the traditional SSR "waterfall bottleneck" using Streaming HTML and Selective Hydration.
1import React, { Suspense } from 'react';23// Shell: Fast, synchronous, flushed immediately!4export function NewsPage() {5 return (6 <div className="layout">7 {/* 1. Flushed in first HTTP chunk: Immediate FCP! */}8 <Header />9 <Navigation />1011 {/* 2. Main content: Fast fetch */}12 <Suspense fallback={<ArticleSkeleton />}>13 <TopArticles />14 </Suspense>1516 {/* 3. Slow comments: Does NOT block Header or Articles from rendering/hydrating! */}17 <Suspense fallback={<CommentsSkeleton />}>18 <SlowCommentsSection />19 </Suspense>2021 <Footer />22 </div>23 );24}2526// Server streaming entry point (Node.js)27import { renderToPipeableStream } from 'react-dom/server';2829export function handleRequest(res: any) {30 const { pipe } = renderToPipeableStream(<NewsPage />, {31 bootstrapScripts: ['/main.js'],32 onShellReady() {33 // First chunk containing Header, Navigation, and fallbacks sent immediately!34 res.setHeader('content-type', 'text/html');35 pipe(res);36 },37 onError(err) {38 console.error('Streaming error:', err);39 },40 });41}
Deep Architectural Explanation
The Death of the SSR Waterfall
The 3 Bottlenecks of Legacy SSR:
- Fetch Bottleneck: The server cannot send ANY HTML until all backend queries finish.
- Download Bottleneck: The browser cannot hydrate until all JavaScript bundles download.
- Hydration Bottleneck: React cannot make any component interactive until every component hydrates.
How React 18 Streaming SSR Solves This:
- Streaming HTML via renderToPipeableStream:
- React immediately renders the outer shell and wraps slow components in fallback skeletons.
- The initial HTML is flushed over the HTTP response in milliseconds.
- As slow components resolve on the server, React streams inline script tags that replace the skeleton with actual HTML in-place!
- Selective Hydration:
- Components wrapped in Suspense do not block other components from hydrating.
- If TopArticles finishes downloading its JS, React hydrates it immediately—even while SlowCommentsSection is still loading!
- Interaction-Driven Prioritization:
- If the user clicks on Comments while React is busy hydrating TopArticles, React pauses hydrating articles and immediately hydrates the clicked comments section to handle the user interaction without lag!
Common Interview Traps & Pitfalls
Wrapping the entire application in a single root Suspense boundary, defeating granular streaming.
Using legacy renderToString which blocks streaming and requires waiting for all promises.
Assuming streamed HTML requires client-side JavaScript execution to display.
Senior Interviewer Follow-Up Probes
How does HTTP chunked transfer encoding (Transfer-Encoding: chunked) enable streaming responses?
How does Selective Hydration interact with Concurrent Mode scheduler priorities?
What is the difference between onShellReady and onAllReady in renderToPipeableStream?
Frequently Asked Interview Questions
What is Selective Hydration?
A feature of React 18 that allows individual subtrees wrapped in Suspense boundaries to hydrate independently as their code loads, rather than requiring the entire page to hydrate in one monolithic pass.
How does React prioritize hydration when a user interacts with the page?
If a user clicks on an unhydrated component, React intercepts the native event, prioritizes hydrating that specific subtree ahead of others, and replays the user interaction seamlessly.
What does renderToPipeableStream do?
The Node.js server rendering API in React 18+ that outputs a readable Node stream of HTML, supporting progressive streaming, Suspense fallbacks, and shell readiness callbacks.
What is onShellReady vs onAllReady?
onShellReady fires as soon as the initial UI shell outside Suspense boundaries is ready to stream to browsers. onAllReady waits until all Suspense boundaries complete, useful for web crawlers/SEO bots.
Can streaming SSR work without JavaScript enabled in the browser?
Yes. The server streams inline scripts that swap skeleton placeholders with real HTML, meaning users see complete rendered HTML even before full client hydration bundles run.
