SSR vs SSG vs CSR: Server-Side Rendering, Static Site Generation and Client-Side Rendering Explained
The same three letters keep showing up in every modern framework's docs — the real question each one answers is simply: at what point does the HTML a browser receives actually get built?
Every modern web framework's documentation eventually gets to this trio of acronyms — SSR, SSG, CSR — and they all answer the exact same underlying question in different ways: at what point does the actual HTML the browser displays get generated? Understanding that one question resolves most of the confusion around when to use which.
Client-Side Rendering (CSR): built in the visitor's browser
In CSR, the server sends a nearly empty HTML shell plus a JavaScript bundle, and the browser itself runs that JavaScript to fetch data and build the actual visible page, entirely on the visitor's device after the page loads. This was the dominant model for single-page applications (classic Create React App, many SPA dashboards) for years — genuinely fast page-to-page navigation once the initial JavaScript is loaded, since subsequent "page changes" just re-render in the browser without a full server round-trip. The trade-off: the very first load is slower (the browser has to download and execute JavaScript before anything meaningful appears), and search engine crawlers historically struggled to see content that only exists after JavaScript execution — a real SEO liability for anything meant to be publicly discoverable and indexed.
Sponsored
Server-Side Rendering (SSR): built fresh, on the server, per request
In SSR, the server runs the rendering logic for every single incoming request, generating complete, ready-to-display HTML before sending it to the browser. The visitor gets meaningful content immediately, without waiting for JavaScript to run first, and search engines see fully-formed HTML on first crawl, with no execution required. The trade-off is server load and response time: since the HTML is built fresh for every request, a spike in traffic means a spike in server-side rendering work, and the time-to-first-byte is inherently tied to how fast the server can generate that specific page's content on demand — a genuinely data-heavy or slow-database-query page can make SSR noticeably slower to respond than a pre-built alternative.
Static Site Generation (SSG): built once, ahead of time
In SSG, the HTML is generated once, at build time — before any visitor ever requests the page — and the resulting static files are then served directly (often via a CDN) to every subsequent visitor, identically, with no per-request rendering work at all. This is the fastest possible option for pages whose content doesn't need to differ per visitor or change on every request — a blog post, a marketing page, a documentation page — since serving a pre-built static file is about as fast as web delivery gets, with essentially zero server-side computation per request. The trade-off: content is only as fresh as the last build — if the underlying data changes, the static page doesn't reflect that change until the site is rebuilt and redeployed (or, in more modern frameworks, until a specific revalidation mechanism refreshes it).
Where this site's own build fits in
This distinction isn't abstract — it directly shapes how a real site like this one is actually built. Reference content that doesn't change per visitor (a blog post, a tool's marketing page) is pre-rendered at build time as static HTML, so every visitor gets an instantly-served page with no server-side work per request; genuinely dynamic content that needs to reflect live, frequently-changing data uses a different strategy, since the value of pre-building goes away the moment the underlying data is expected to differ from one moment to the next.
Incremental Static Regeneration (ISR): a hybrid worth knowing
Modern frameworks (Next.js, most notably) add a fourth option that blends SSG's speed with SSR's freshness: Incremental Static Regeneration, where a static page is served instantly like SSG, but the framework automatically regenerates it in the background after a specified time interval or on-demand trigger, so subsequent visitors eventually get the refreshed version without needing a full site rebuild and redeploy. This solves SSG's core weakness (staleness) without paying SSR's full per-request rendering cost on every single visit — most visitors still get an instantly-served static file, and only occasionally does a request trigger the background regeneration work.
Hydration: the step that makes SSR/SSG pages interactive
There's a detail worth understanding for both SSR and SSG: the HTML delivered to the browser is initially static markup, not yet interactive — clicking a button or typing into a form won't do anything until JavaScript downloads and hydrates the page, attaching event handlers and making the pre-rendered markup behave like a real, interactive React (or similar framework) application. This means SSR and SSG's speed advantage is specifically about *visible content* appearing fast, not necessarily *full interactivity* appearing fast — a page can look complete and readable well before it's fully interactive, which is usually the right trade-off (a visitor can start reading immediately) but is worth knowing about if a specific page needs to be interactive the instant it's visible, not just visible.
Streaming and partial rendering: reducing the wait further
Modern frameworks have also introduced streaming SSR, where the server sends parts of the HTML as they become ready rather than waiting for the entire page's data to be gathered before sending anything — a page with a fast-loading header and a slower-loading data table can show the header immediately while the table streams in moments later, rather than blocking the whole response on the slowest piece. This meaningfully softens SSR's main weakness (response time tied to the slowest data dependency) without giving up SSR's core benefit of delivering real, crawlable content on the first response.
SEO implications, concretely
Both SSR and SSG deliver fully-formed HTML on the very first response, which search engine crawlers can read directly without needing to execute JavaScript first — a genuine, measurable SEO advantage over pure CSR, where a crawler historically needed to run JavaScript (something major crawlers have gotten better at over time, but still less reliable and slower than reading ready-made HTML directly) to see the actual content. For any page where organic search visibility matters — which, per this site's own SEO-first approach, is essentially every public-facing page — SSR or SSG is the safer default, and pure CSR is reserved for content genuinely behind a login or otherwise not meant to be publicly indexed anyway.
Performance trade-offs beyond the SEO question
- Time to First Byte (TTFB): SSG wins decisively (a pre-built file needs no computation); SSR is slower and variable (depends on per-request rendering time); CSR's initial HTML arrives fast but is largely empty, so it doesn't reflect *meaningful* content speed.
- Time to meaningful content: SSG and SSR both deliver meaningful content in the initial response; CSR delays meaningful content until JavaScript downloads and executes, which is slower on poor connections or lower-powered devices.
- Server cost at scale: SSG is cheapest to serve at high traffic (static files, trivially cacheable); SSR costs scale with traffic since every request triggers real server-side work, unless aggressively cached.
- Content freshness: SSR is always fresh (built per request); SSG is only as fresh as the last build unless paired with ISR or on-demand revalidation; CSR is inherently fresh since it fetches live on each load.
How caching interacts with each strategy
Caching adds another layer worth understanding on top of the base rendering strategy. SSG output is trivially cacheable — the same static file serves every visitor, so a CDN can cache it at the edge indefinitely (until the next build). SSR output *can* also be cached (many frameworks and CDNs support caching an SSR response for a defined period, effectively borrowing SSG's speed benefit for content that doesn't need to be rendered fresh on literally every single request), but this requires deliberate configuration — SSR without any caching layer means genuinely rendering from scratch every time, while SSR with a sensible cache policy can approach SSG-like performance for content that changes only occasionally rather than per-request. CSR's client-fetched data can similarly be cached client-side or via a data-fetching library, reducing repeated network requests for data that hasn't changed.
A practical decision guide
- Choose SSG if: the content is the same for every visitor and doesn't need to reflect real-time changes — blog posts, marketing pages, documentation, product catalogs that update on a normal deploy cadence.
- Choose SSR if: content genuinely needs to be fresh and personalized per request — a user's live dashboard, search results reflecting current inventory, anything where serving even slightly stale data would be a real, visible problem.
- Choose CSR if: the content is behind authentication anyway (so SEO doesn't apply), and the priority is fast subsequent in-app navigation over a fast very-first load — a genuine application-like dashboard or tool where users stay for an extended session after one initial load.
- Consider ISR if: you want SSG's raw speed for most requests but can't tolerate fully stale content indefinitely between deploys — a good middle ground for content that changes periodically but not on every single request.
Why this matters more now than it used to
This distinction has become more practically relevant over time, not less, as the tooling for mixing strategies within one project has matured — a decade ago, choosing SSR generally meant committing an entire application to a server-rendering architecture, and choosing a static site generator meant committing to a purely static one, with real engineering cost to combine them. Modern frameworks have largely removed that all-or-nothing trade-off, which is precisely why the practical question shifted from "which one should our whole site use" to "which one fits this specific page" — the flexibility genuinely exists now in a way it didn't a decade ago, so not taking advantage of it on a per-page basis usually leaves real, easily-captured performance and SEO benefit on the table.
A common misconception: frameworks, not just strategies
It's worth being precise about terminology here — SSR, SSG and CSR are rendering strategies, not frameworks themselves, and most modern frameworks (Next.js, Nuxt, SvelteKit, Remix, and others) support more than one of these strategies, often on a per-page or per-route basis within the same application, rather than forcing an entire site into one single approach. Choosing "a framework that does SSR" isn't really the right framing — the more useful question is which strategy fits each specific page's content, and whether the framework you're evaluating makes it easy to mix strategies across a single project without major friction.
The short version: SSR, SSG and CSR all answer the same question — when does the actual HTML get built — just at different points: per-request on the server (SSR), once ahead of time at build (SSG), or in the visitor's own browser after the page loads (CSR). Most real, modern sites use more than one strategy across different page types rather than picking a single approach sitewide, matching each page's actual freshness and personalization needs rather than forcing every page through the same rendering pipeline.
If there's one practical takeaway to carry forward, it's to resist treating this as a single, sitewide architectural decision made once at the start of a project. The more useful habit is asking the question per page or per route: does this specific content need to be fresh on every request, is it fine being rebuilt periodically, or does it only make sense once a user is already authenticated and interacting with it? Answering that question honestly, page by page, produces a faster, more correctly-behaved site than defaulting every route to whichever strategy happened to be the framework's starting template.
It's also worth revisiting these choices as a project matures rather than treating an early decision as permanent — a page originally built as client-rendered because it started out behind a login might later become worth exposing publicly and pre-rendering for SEO, and a statically generated page that was once genuinely static might later need real-time data as the product grows. Rendering strategy is an implementation detail that should follow a page's actual current requirements, not a historical decision inherited from however the project happened to be scaffolded originally.
None of this needs to be perfectly optimized from day one, either — starting with the simplest strategy that reasonably fits a page's needs, then revisiting it if that page's real-world traffic or freshness requirements turn out to be different than expected, is a far more practical approach than trying to predict every future requirement before writing the first line of a new route.
Tools used in this article
Sponsored
Frequently asked questions
For time-to-first-byte, yes — a pre-built static file requires no per-request computation, while SSR renders fresh HTML on every request. SSR's advantage is that its content is always current, which SSG alone doesn't guarantee.
TechToolsCenter Team
Product & Tools
The team behind TechToolsCenter — building fast, private, browser-based tools and writing practical guides on how to get the most out of them.
Related articles
CSS Container Queries Explained: What They Are and When to Use Them
Media queries respond to the whole viewport; container queries respond to the space a component actually has — which is what "responsive" should have meant for reusable components all along.
What Is Rate Limiting, and How Does It Actually Work?
A 429 error isn't your code failing — it's an API telling you, quite specifically, to slow down. Here's what's actually enforcing that, and how to work with it instead of against it.
CORS Explained: Why Your API Requests Get Blocked (and How to Fix It)
"Blocked by CORS policy" is one of the most common errors in web development — and one of the most commonly misunderstood, since the fix almost never lives where the error appears.