awesome-everything RU
↑ Back to the climb

Browser & Frontend Runtime

SSG, SSR, ISR, streaming, and RSC — how each works

Crux The mechanism behind each rendering strategy: SSG''''s CDN path, SSR''''s critical-path cost, ISR''''s stale-while-revalidate model, streaming''''s shell-first flush, and RSC''''s server-only bundle reduction.
Your altitude — climbing toward senior
ZeroJuniorMiddleSenior
You are at middle altitude — in the sky
◷ 18 min

A product page price changes twice a day. A logged-in dashboard is different for every user. A blog post is the same for everyone. These three facts imply three different rendering strategies — and picking the wrong one means paying for server compute on every request when a CDN cache hit would do, or serving a stale price for 12 hours when ISR could cap staleness at one hour.

SSG: render at build time. Static Site Generation runs the components once, during the build, and writes the result to HTML files deployed on a CDN. The request path is unbeatable — no server compute, an edge cache hit, time-to-first-byte in tens of milliseconds. The cost is freshness and scale: content is frozen at build time, and a million-page site takes a long time to rebuild. SSG is the right default for anything whose content does not change per request and per user: marketing pages, docs, blog posts. The moment the page must reflect “now” or “this specific user,” pure SSG breaks down.

SSR: render per request. Server-Side Rendering runs the components on the server for every request, producing fresh HTML each time. It can read the user’s cookies, the current time, live data — the HTML is exactly right for this request. The cost is on the critical path: the user’s time-to-first-byte now includes the server’s render time plus any data fetching it does. A slow database query in the render is a slow TTFB for the user. SSR also means you run and pay for server capacity that scales with traffic. SSR is right when the page must be per-request fresh or per-user personalised — a logged-in dashboard, a feed, search results.

ISR: SSG that refreshes itself. Incremental Static Regeneration is SSG with a revalidation rule. The page is served static from cache, but after a configured time — or on an explicit on-demand trigger — the next request gets the stale copy while the server regenerates a fresh one in the background; subsequent requests get the new version. It is stale-while-revalidate applied to whole pages. ISR is the answer to “mostly static, but the content does change — a product page whose price updates a few times a day.” You get SSG’s instant delivery for the overwhelming majority of requests and bounded staleness instead of a full rebuild.

Freshness spectrum — frozen to live

SSG
build
frozen at build, instant CDN hit
ISR
build + interval
stale-while-revalidate for pages
SSR
per request
fresh, TTFB = server render + data fetch
CSR
in browser, after fetch
freshest, empty shell first

Streaming SSR: send the HTML in chunks. Plain SSR has a blocking flaw: the server must finish rendering the entire page — including its slowest data fetch — before it can send a single byte. If one widget needs a 400 ms query, every user waits 400 ms for time-to-first-byte. Streaming SSR fixes this. With renderToPipeableStream, the server sends the shell immediately, and each <Suspense> boundary streams in as its data resolves. The user sees the header, nav, and layout in ~50 ms; the slow widget arrives 400 ms later as a streamed chunk that the browser slots into place. TTFB drops to the speed of the fastest part of the page, not the slowest.

React Server Components: components that never ship to the client. RSC is a different axis entirely. A Server Component runs only on the server — its code is never sent to the browser. It can read the database directly, use server-only secrets, and import heavy libraries (a markdown parser, a syntax highlighter) that cost the client nothing because they never cross the wire. Its output is not HTML and not a JS bundle — it is a special serialised format, the RSC payload, describing the rendered tree. Client Components (marked 'use client') are the interactive islands within that tree; only their code ships. The win is bundle size: parts of your app that are just “display server data” carry zero client JavaScript.

Why this works

RSC and SSR are often confused as competing. They are orthogonal. SSR is about when and where the HTML is generated. RSC is about which components ship code to the client at all. A production Next.js App Router page typically uses both: Server Components run on the server and produce HTML via SSR (often streamed), and the Client Components within are also server-rendered to HTML for first paint and then hydrated. RSC reduces how much there is to hydrate; SSR/streaming controls when the HTML appears.

Quiz

A product page must show a price that updates a few times a day, and must load instantly for the vast majority of visitors. Which strategy fits best?

Quiz

Plain SSR has one widget that needs a 400 ms database query. How does streaming SSR change the user's time-to-first-byte?

Quiz

What is the bundle-size benefit of a React Server Component?

Order the steps

Order these render strategies by how fresh their HTML is — from frozen-at-build to fresh-every-request.

  1. 1 SSG — rendered once at build time
  2. 2 ISR — static, regenerated on a revalidation interval
  3. 3 SSR — rendered fresh on every request
  4. 4 CSR — rendered in the browser, after fetching live data
Compute it

Plain SSR waits for the slowest data fetch — say 400 ms — before sending any HTML. Streaming SSR sends the shell as soon as it is ready, ~50 ms. Roughly how many milliseconds of time-to-first-byte does streaming save here?

ms
Recall before you leave
  1. 01
    Why is SSG the right default for docs and marketing pages, but wrong for a logged-in dashboard?
  2. 02
    How does ISR work as stale-while-revalidate for pages?
  3. 03
    What is the Suspense boundary's role in streaming SSR?
Recap

SSG wins on TTFB — tens of milliseconds, CDN edge hit, no server compute — but the content is frozen at build time and a full rebuild is required to update it. SSR trades that speed for freshness: every request runs the component tree on the server with live data, but the user’s TTFB now includes server render time and any data fetches. ISR sits in between using stale-while-revalidate: pages are served static, and after a revalidation interval the server regenerates in the background while the stale copy is still served — perfect for content that changes on a known cadence. Streaming SSR changes the unit of waiting from the whole page to individual Suspense boundaries: the shell arrives at ~50 ms and slow widgets stream in as their queries resolve. RSC cuts a different cost: by running entirely on the server, Server Components never contribute to the client bundle or hydration surface — large libraries and data-fetching code stay on the server, and only the interactive Client Component leaves ship JS.

Connected lessons
appears again in267
Continue the climb ↑Hydration cost: selective, progressive, islands, resumability
shortcuts expand
search
K
prev piece
k
next piece
j
cycle tier
t
this menu
?
sources4
expand
  1. 01
  2. 02
  3. 03
  4. 04

Trademarks belong to their respective owners. Editorial reference only.