Definition
This is the doc that separates what actually improves from what stays the same, when you expect switching SSR to streaming to raise your Lighthouse score. Streaming SSR (streaming server rendering) is the approach where, instead of the server awaiting the entire tree and then sending the HTML all at once, it flushes the shell (the skeleton HTML sent first) and Suspense boundaries (React boundaries that show fallback UI while waiting for data and fill it in once ready) in chunks (Next.js App Router's streaming RSC, etc.; RSC = React Server Component). The Lighthouse (Google's performance tool) · lab CWV (Core Web Vitals measured in a lab environment) gains are determined less by streaming itself and more by which chunk the LCP candidate (the largest content element) sits in.
Why it matters
ssr-prefetch-query-cache-hydration reduces the waterfall (a cascading delay where a later request can't start until the earlier one finishes) on the client where session → api/data requests chain in order. Streaming is a different axis — when the server starts sending HTML bytes. Conflating the two creates the wrong priority of "just turn on streaming and Lighthouse goes up." On a page where LCP is tied to API results, like an auth-gated home (a home whose content differs by login state), deferring the data LCP needs to a later Suspense may improve only FCP (First Contentful Paint, when the first pixels are painted) while LCP stays put or CLS (Cumulative Layout Shift, how much the screen shifts as content fills in later) worsens.
How it works
| Pattern | First byte / shell | LCP element |
|---|---|---|
| Blocking SSR (await all) | slow (TTFB↑) | paint all at once after data is ready |
| Stream, LCP late | shell first | LCP in a later chunk — FCP↑, LCP≈ |
| Stream, LCP early | shell + LCP data | only secondary deferred — FCP↑, LCP↑ possible |
Lighthouse Performance is a lab score that weight-composites LCP · TBT · CLS · FCP · SI, etc. (lighthouse-measurement-accuracy). Even if only the shell comes out fast, FCP / Speed Index can rise while LCP ms doesn't move. Don't conclude "it got better" from the score alone.
Relationship with prefetch:
- Prefetch + hydrate — removes the in-browser waterfall.
- Streaming — room to overlap CSS/JS parsing · shell paint while waiting on the same server wait.
- If prefetch is already the crux of the LCP path, streaming's added gain is usually on the deferring auxiliary data side.
Practical application
- LCP-critical in the front chunk — put auth + the meta LCP needs (first image URL, etc.) in a blocking prefetch or the first stream (carousel-viewport-image-deferral).
- Only secondary in Suspense — stream-defer below-fold widgets, auxiliary queries, non-LCP panels.
- Skeleton set — CLS occurs if you don't reserve height · row count when the later chunk attaches (cls-skeleton-layout-reservation).
- Measure — separate the Lighthouse score from the trace LCP ms, and do before/after with the median of N runs in a production
build && start(lab-performance-measurement-variance).
Tradeoffs
| Choice | Benefit | Cost |
|---|---|---|
| Blocking + LCP prefetch | simple · predictable LCP path | TTFB · first paint delay |
| Stream, LCP early | can improve FCP/SI + LCP together | boundary design · chunk-order complexity |
| Stream, LCP late | shell · FCP perceived | no LCP gain · CLS risk |
| Prefetch only (no stream) | removes client waterfall | no shell flush gain |
When not to use
- Public static pages — when CDN/SSG alone suffices.
- Leaving the LCP element as only a "slot to be filled later" and banking streaming's gain on the LCP SLA.
- Putting a large block into a later chunk without a skeleton · layout reservation.
Common mistakes
- Assuming adopting streaming = automatic Lighthouse Performance rise.
- Deferring the LCP-critical API to a later Suspense and recording the FCP-only improvement as a success.
- Treating prefetch and streaming as the same optimization and swapping the priority.
- Looking only at the score without re-measuring LCP ms · CLS.
Related concepts
- ssr-prefetch-query-cache-hydration — client waterfall vs HTML flush axis
- largest-contentful-paint — LCP candidate · improvement
- lighthouse-measurement-accuracy — score vs trace ms
- cls-skeleton-layout-reservation — stream chunk + skeleton
- carousel-viewport-image-deferral — only LCP meta early, defer the bytes
- lab-performance-measurement-variance — compare the median of N runs