Performance
Streaming SSR
Streaming SSR is sending HTML to the browser in chunks as sections finish rendering, instead of waiting for the whole page. The head and shell can arrive while slower data is still loading.
How it is measured
In DevTools a streamed response shows a short TTFB and a long content download bar. Curl with `--no-buffer` shows the body arriving in pieces. Compare TTFB and FCP with the non-streaming version of the same route.
Frameworks such as React 18, with `renderToPipeableStream`, flush a shell and Suspense fallbacks first, then stream replacements for each boundary as its data resolves. Measure the time from first byte to each boundary being filled in.
Worked example
A dashboard page needs a user header (20 ms), a billing summary (180 ms), and a recommendations panel (1.2 s from a slow service). Plain SSR sends nothing until about 1.25 s, so TTFB is 1.25 s and FCP 1.5 s.
Streaming sends the shell with the header at 60 ms, billing at 240 ms, and recommendations at 1.3 s, with a skeleton in between. TTFB is 60 ms and FCP is 0.4 s.
How it differs
Streaming SSR sends the page in pieces. Plain server-side rendering sends one piece after everything is ready. Streaming removes the all-or-nothing wait, but status code and headers cannot change after the first chunk, and caching the whole page gets harder.
Common errors
Putting the slow data above the shell. Forgetting that proxies and CDNs may buffer chunks and defeat streaming. Trying to set the HTTP status after streaming has started. Using skeletons that cause layout shift. Letting compression buffer the flushes.
In practice
Find the slowest data dependency on your busiest dynamic page and wrap it in a Suspense boundary with a fixed-height fallback. Check with `curl --no-buffer` that chunks arrive spaced apart, and confirm your CDN does not buffer them.