EMZETT.
Login

Rendering strategies: SSR, SSG, ISR and client rendering compared

In short: A web page can be generated at build time (SSG), on every request (SSR), periodically anew (ISR) or in the browser (CSR); the choice affects speed, freshness, cost and search-engine suitability.

In more detail: The question is: when and where does the HTML arise? Frameworks such as Next.js let you choose this per page.

In Depth

The strategies

  • SSG (static site generation): HTML is generated at build time and delivered via a CDN. Very fast, cheap, safe; but only as current as the last build. Ideal for blog, docs, wiki, landing pages.
  • SSR (server-side rendering): the server generates the HTML on every request; always current and personalisable (cookies), but slower and more expensive (compute time, possibly database).
  • ISR (incremental static regeneration): static page with expiry (revalidate: 3600); after expiry it is rebuilt in the background. Good compromise for lists, shops, news.
  • CSR (client-side rendering): the browser loads JavaScript and builds the page; good for dashboards behind login, worse for first load time and SEO.
  • Streaming/Suspense: the page is delivered in parts; important things appear first.

Decision aid

RequirementChoice
Rarely changing content, much trafficSSG
Content changes every minute/hourISR
Different per user (cart, profile)SSR or CSR
Behind login, interactiveCSR (or SSR + client components)
SEO importantSSG/ISR/SSR
Hybrids are normal: static shell, dynamic parts via streaming or client query.

Effects

  • Database load: SSR/ISR query it; with caching (see unstable_cache, revalidate) and long expiry times load falls sharply, especially with serverless databases that pause when idle and bill compute time.
  • Cost and speed: CDN delivery of static pages is cheapest.
  • Resilience: static pages keep running even if the database is unreachable; builds therefore must not depend on the database or must catch errors.
  • Freshness: with on-demand revalidation (tags/paths) you can rebuild specifically after changes.

Practice

Start static, add dynamics where needed. Measure with Lighthouse/Core Web Vitals (LCP, CLS, INP). Set cache headers suitably. Test behaviour on database outage and cold starts. In Next.js: export const revalidate = 3600, dynamic = 'force-dynamic', generateStaticParams, server components with fetch and cache options (check the docs of your version, the API changes).

See also: Next.js App Router, Caching strategies, Cache tags and revalidateTag, Lighthouse and Core Web Vitals, Serverless