Articles

SSR vs SSG: Server-Side Rendering vs Static Generation

SSR renders pages per request; SSG renders them at build time. How the tradeoff affects speed, freshness, and hosting cost — and how to pick.

Takina Takina · · 4 min read
Abstract illustration representing the web platform

Server-side rendering (SSR) generates a page’s HTML on the server for every incoming request. Static site generation (SSG) generates that HTML once, at build time, and serves the identical file to every visitor afterward. Both produce full HTML before it reaches the browser — the difference is when that rendering happens, and that single distinction cascades into very different tradeoffs around speed, cost, and how fresh the content can be.

What both are reacting to

Client-side rendering — where the server ships a mostly empty HTML shell and JavaScript builds the page in the browser — has a well-known cost: the user stares at a blank or skeleton page until the JavaScript bundle downloads, parses, and executes. SSR and SSG both exist to avoid that by sending real, visible content in the first response. The browser still needs to attach interactivity afterward — a process called hydration — but the page is legible and often usable before that finishes.

Server-side rendering

With SSR, every request hits the server, which runs the rendering logic — often fetching data from a database or API — and returns fresh HTML. Because this happens per request, SSR pages can reflect real-time data: a logged-in user’s dashboard, live inventory counts, personalized content.

The cost is that every request does real work. Rendering takes server CPU time and, if it needs data, a round trip to a database or API before the response can even start. That per-request cost is why SSR pages typically need application servers running continuously, plus caching layers to keep response times acceptable under load — see what a load balancer does to spread that load, and what a reverse proxy does to sit in front of it and often cache responses.

Static site generation

With SSG, the entire site — or every page whose content is knowable ahead of time — is rendered once during a build step, producing plain HTML files. Those files get uploaded to a CDN and served directly, with no server-side rendering work happening per request at all.

This is about as fast as serving a page can get: no database query, no template rendering, no backend logic in the request path — just a static file coming from an edge location close to the visitor. It’s also cheap to host and scales to enormous traffic without extra infrastructure, since a CDN serving static files doesn’t care whether it’s handling ten requests a second or ten thousand.

The tradeoff is freshness. If the underlying content changes, the static HTML doesn’t know until the site is rebuilt and redeployed. That’s fine for a blog post or documentation page that changes occasionally, and it’s exactly the model this site itself uses — see deploying an Astro site to Cloudflare Pages for a concrete build-and-deploy pipeline. It’s a poor fit for a page that needs to show something different for every visitor or every second.

Head-to-head

SSRSSG
When rendering happensPer requestAt build time
Time to first byteDepends on server + data fetchNear-instant (served from CDN)
Content freshnessAlways currentFixed until next build/deploy
PersonalizationNativeNot possible without client-side fetching
Server infrastructureRequires a running application serverStatic file hosting is enough
Scaling costGrows with traffic and render costFlat — a CDN handles scale
Best forDashboards, feeds, personalized or real-time pagesBlogs, docs, marketing pages, product pages that don’t change per visitor

The hybrid middle ground

Most real frameworks don’t force an all-or-nothing choice anymore. Incremental static regeneration and on-demand revalidation let a page start out statically generated but get rebuilt in the background after a set time or when triggered by a content change — combining SSG’s speed with something closer to SSR’s freshness, without paying the per-request rendering cost on every single visit.

Another common pattern is rendering the page’s shell statically while fetching personalized or frequently changing pieces client-side after load — effectively mixing SSG for the parts that don’t change per visitor with a lightweight client fetch for the parts that do. This is related to, but distinct from, React Server Components, which change where component logic runs rather than when — it’s a separate axis from the build-time-vs-request-time question SSR and SSG answer.

How to choose

A few questions usually settle it:

  • Does the content differ per visitor? If yes — a dashboard, an account page, search results — SSR (or client-side fetching) is required. SSG physically can’t produce per-visitor HTML at build time.
  • How often does the content change, and does staleness matter? A changelog that updates weekly is a great SSG candidate. A stock ticker is not.
  • What’s the traffic pattern? High, spiky, or unpredictable traffic favors SSG’s flat CDN-serving cost over SSR’s per-request server load — this is a big part of what Core Web Vitals scoring rewards, since a cached static response reliably beats a server render on time-to-first-byte.
  • What’s the operational budget? SSG needs a CDN and a build pipeline. SSR needs a running server (or serverless functions) that scales with traffic, plus the monitoring and capacity planning that comes with it.

The takeaway

SSR and SSG both send fully-formed HTML to the browser instead of an empty shell — the difference is whether that HTML is built fresh on every request or once ahead of time. SSG wins on speed, cost, and simplicity whenever content doesn’t need to differ per visitor or update in real time; SSR is the right call when it does. Most production sites end up mixing both, statically generating what doesn’t change per request and rendering on the server (or fetching client-side) what does.

Takina Takina · · 4 min read

What Is the Beacon API? navigator.sendBeacon()

The Beacon API lets a page send one last async request as it unloads, without blocking navigation or racing the browser's page teardown.

#Web Development #Frontend #Performance
Takina Takina · · 5 min read

CSS will-change Explained: Compositing and Performance

The CSS will-change property hints the browser to prepare an element for an upcoming change, moving it to its own compositor layer. When to use it and when not to.

#CSS #Web Development #Performance