Rendering Strategies — Cheat Sheet

FE Lead prep · ref 09 · CSR / SSR / SSG / ISR / streaming / RSC · §2.1 near-certain Q

The frame — ONE axis

WHERE (browser / server / build) & WHEN (build-time / request-time / on-demand) is the first-paint HTML built — & how much JS do we ship to hydrate it? Six acronyms = points on one spectrum. Pick per surface, not per app.

The family (what each optimizes / when)

StrategyBuild where/whenWins / costs · pick when
CSRbrowser, request-timefast TTFB, slow FCP, bad SEO · app-like, gated, no-SEO dashboards
SSRserver, per requestfast FCP + SEO + fresh; TTFB grows + hydration tax · dynamic + SEO + per-req data
SSGbuild machine, build-timebest TTFB/FCP, cheap, CDN; stale till rebuild · content stable between deploys
ISRbuild-time + bg regenstatic speed + eventual freshness (SWR for pages) · millions of mostly-stable pages
Streaming SSRserver, flush in chunksTTFB not hostage to slowest query; via <Suspense> · slow part + fast part
RSCserver, 0 JS shippedless hydration → better INP; needs server runtime · data/library-heavy pages

Metrics they trade

Hydration tax (why streaming/RSC exist)

Server sends HTML → browser downloads JS → re-runs tree to attach handlers = redo server work on weak device. Inert till done (uncanny valley) → top cause of bad INP.

Streaming SSR + Suspense

<SearchResults />                        // fast → flush now
<Suspense fallback={<Skeleton/>}>
  <Reviews />                            // slow → stream in when ready
</Suspense>
Classic SSR = all-or-nothing: no HTML till every fetch resolves + can't hydrate till whole bundle loads. Streaming flushes shell now, streams slow subtree later; React selectively hydrates chunks + prioritises what user clicks.

RSC — pay down the JS itself

async function HotelPage({id}){          // Server Component (default) = 0 KB client
  const h = await db.hotels.find(id);   // DB/heavy libs stay server-side
  return <article>{h.name}<BookButton id={id}/></article>;
}
// BookButton.tsx
"use client"   // ← only islands ship JS & hydrate

Platform whiteboard — per surface

SurfaceStrategy · why
Marketing / city / SEO contentSSG/ISR — static at edge, ISR refreshes prices w/o full rebuild
Search results listingStreaming SSR + edge cache — SEO + fast FCP, facets/reviews stream in
Filters / datepicker / mapClient island (CSR) — interactive, no SEO; small "use client"
Hotel detail (millions)ISR + streaming — static + revalidate; stream live price/availability
Checkout / accountFresh SSR, no-store — personalized, correctness-critical, behind auth
+ cross-cutting: edge-cache logged-out HTML · code-split per route · i18n locale routing + hreflang · RUM p75 LCP/INP across markets.

PPR — Partial Prerendering (the synthesis)

Collapses static-vs-dynamic from per-ROUTE → per-COMPONENT, one response. Build-time: prerender static shell (outside <Suspense>). Request-time: shell ships instant from edge; dynamic holes (inside Suspense, read cookies()/headers()/searchParams) stream into the same response. Static TTFB + dynamic freshness, no client waterfall.

Lead one-liners (memorize)

Frame  "Not six choices — one axis: where & when the HTML is built. I pick the point per surface that balances TTFB, first paint, interactivity, freshness."
Per-surface  "No single right strategy — static for content, streaming-SSR for the SEO listing, a client island for filters, fresh-SSR for checkout."
Streaming  "Classic SSR is hostage to its slowest query and hydrates all-or-nothing. Suspense flushes the shell now and streams the slow parts in."
RSC  "Streaming makes hydration arrive sooner; RSC makes there be less of it — the cheapest hydration is the one you never do."
PPR  "PPR collapses the static-vs-dynamic call from per-route to per-component — a static shell from the edge with dynamic holes streamed into the same response. Islands inverted."

Sources: web.dev — Rendering on the Web · patterns.dev — Rendering Patterns · react.dev — Server Components · react.dev — Suspense · Next.js — ISR

Don't fail the interview

1. It's one axis (where/when HTML is built), not 6 separate things. Pick per surface — "SSR everything" is a junior tell.
2. SSG vs SSR = WHEN (build-time static vs per-request), not where. Both render off-browser.
3. "SSR is always faster than static" = false. Static from CDN wins TTFB; SSR's TTFB grows with server work.
4. Hydration tax = client re-runs the tree to attach handlers → main-thread work → hurts INP. Inert UI = uncanny valley.
5. Classic SSR TTFB is hostage to the slowest query. Streaming + <Suspense> flushes shell now, streams slow parts.
6. RSC ships 0 JS for server components → less hydration. Server still in picture; props across boundary must be serializable.
7. ISR = SSG + background revalidate = SWR for whole pages. The answer to "millions of mostly-stable pages, prices change."
8. PPR = static shell (edge) + dynamic holes (streamed) in one response; per-component not per-route. "Islands inverted." Frontier / Next-specific.