Where Does the HTML Come From: SSR, CSR, SSG, ISR on One Path

Whenever someone asks me how SSR differs from SSG, I never want to just recite the definitions. Memorise the acronyms today, and the next framework with a fresh marketing term sends you back to memorising them all over again. There’s only one question that actually lasts: the HTML the user is looking at in the browser right now — when, and where, was it generated? Get that clear and the acronyms collapse into a few points on a single path.

The path itself is plain. Someone fires a request, something somewhere fills data into a template, HTML comes out, and the browser renders it. The only thing that varies is when the “fill data, produce HTML” step happens, and which machine it happens on.

One Path, Four Cut Points

SSR runs the server on every request: it assembles HTML from the data as it stands at that moment and sends it back. The first document the user receives is already complete, and the data is fresh as of right now. CSR flips that — the server ships a near-empty shell, and the real content only appears once the browser has downloaded the JS, run it, and called the API. The whole first-paint burden lands on the client. SSG happens earliest of all: the HTML is generated at build time and saved as static files, so a request just hands back something that already exists. Fast, but the content is frozen at your last build.

ISR patches the hole in SSG. The pain with pure SSG is that any data change means rebuilding the whole site, and once the site is large that gets painfully slow. ISR generates a batch at build time, then lets a given page regenerate on demand in the background once it goes “stale”, swapping the fresh version into the cache when it’s ready. So you get static-file speed without rerunning the entire site to fix one article.

By this point the pattern is clear: these four terms are just different answers to the same question — where do you do the work of producing the HTML? At build time, on the first request, or on every request? SSG does it at build, SSR on every request, ISR sits between the two, and CSR pushes the step out to the browser entirely. However glossy the framework’s branding, it can’t escape that axis.

Why the Mental Model Beats the Acronyms

Acronyms go stale and framework marketing reinvents itself every year, but “where is the HTML generated” doesn’t move. Once you think this way, any new framework or render mode prompts you to ask the four right questions instead of being led around by its naming.

First, how fresh does the data need to be? Put prices, stock levels, or a live leaderboard on SSG and users will see stale numbers. Conversely, recomputing a technical article that changes once a quarter on every single request is just burning server time. Second, who bears the compute? SSR charges the cost of assembling HTML to your servers, which gets tested the moment traffic spikes. CSR offloads it onto the user’s browser, which means a cheap phone struggles. Third, how does the cache get invalidated? SSG and ISR are fast because there’s a static file to serve, but the instant a cache is involved you have to answer when, and on what condition, the stale version gets replaced — get that wrong and users stare at outdated screens. Fourth, who owns the first paint? SSR and SSG send a first document that already has content, which is kind to SEO and to perceived load speed. CSR’s first paint is empty until the JS finishes running.

Take a single page through all four modes and the trade-offs surface immediately. An e-commerce product page: on SSG it’s fast but the price and stock may be stale; on SSR it’s always current but every request taxes the server; on ISR it serves a static file most of the time and refreshes in the background every few minutes, striking a balance between price freshness and server cost; on pure CSR the HTML returns instantly but the user watches a skeleton until the data loads, and SEO suffers. None of these is simply right. It all comes down to whether you’d rather trade freshness for latency, or server cost for freshness.

So the order should be reversed. Work out first where this page’s HTML ought to be generated — that’s a design decision about data freshness, compute cost, and cache boundaries. Only then go back and look at which framework, which render mode, happens to implement the cut point you decided you wanted. Picking the framework feature first and reverse-engineering a justification afterwards is usually how the naming starts making your decisions for you.

Key Takeaways

  • Don’t memorise the acronyms — ask first when and where the HTML the user just received was generated.
  • SSR, CSR, SSG, and ISR are different cut points on one request→HTML path; the difference is whether HTML is produced at build, on every request, or in the browser.
  • Once you understand the point of generation, the right questions follow: how fresh is the data, who bears the compute, how the cache invalidates, who owns the first paint.
  • Running one page through all four modes is really a trade-off between freshness, latency, and server cost — there’s no universal best.
  • Decide where the HTML is generated first, then pick framework features; don’t let a framework’s naming make the design decision for you.

Sheng’s take, drafted with Claude · part of the 2026-06-13 blog renovation, paint still drying.