Back to Performance
Performance
easy
mid

What are the differences between server side rendering and client side rendering?

SSR (server-side rendering): server generates HTML per request, ships fully-rendered page; browser shows content immediately, then hydrates JS. Fast first paint, SEO-friendly, but every request hits server. CSR (client-side rendering): server ships empty shell + JS bundle; browser downloads, parses, executes, then renders. Slower first paint, worse SEO, but lighter server. SSG/ISR are SSR variants where HTML is pre-generated. Pick per page: SSR/SSG for content + SEO, CSR for authenticated apps.

9 min read·~5 min to think through

Two ways to render a web page. The choice determines first-paint speed, SEO, server cost, and complexity.

SSR — Server-Side Rendering

Server runs the app, generates HTML, sends it to the browser. Browser displays content immediately; React/Vue hydrates to attach event handlers.

ts
Browser request → Server runs app → HTML with content → Browser paints → JS hydrates

Timeline (typical):

  • TTFB: server response time (50–500ms).
  • FCP/LCP: as soon as HTML arrives + critical CSS applied (1–2s).
  • Interactive: after JS bundle loads + hydrates (2–4s).

Pros:

  • Fast first paint — user sees real content immediately.
  • SEO works out of the box (crawlers see content).
  • Social previews work (OG tags in initial HTML).
  • Lower JS execution burden on low-end clients.

Cons:

  • Server cost per request (no CDN cache by default).
  • Slower TTFB than SSG (server has to render).
  • Hydration mismatch bugs if server + client see different state.
  • Stateful — needs framework support (Next.js, Remix, Nuxt, SvelteKit).

CSR — Client-Side Rendering

Server ships a tiny HTML shell (<div id="root"></div>) + JS bundle. Browser downloads, parses, executes, and renders the app.

ts
Browser request → Empty HTML + JS → Download/parse JS → Render → Fetch data → Re-render

Timeline (typical):

  • TTFB: trivial (static shell, often <100ms from CDN).
  • FCP: after JS bundle loads + parses (2–4s on mid-range mobile).
  • LCP: after data fetches + renders (3–6s).
  • Interactive: similar to LCP.

Pros:

  • Server is dumb (static shell + JSON API) → cheap, scales horizontally.
  • Easy to deploy (drop files on CDN).
  • Snappy in-app navigation after initial load (no full reload).

Cons:

  • Slow first paint (blank screen until JS loads + executes).
  • Bad SEO for non-Google crawlers (they don't run JS).
  • Social previews broken (OG tags injected by JS aren't seen).
  • Heavy on the client (parse + execute large bundles).

SSG and ISR — SSR's better-cached cousins

SSG: Pre-render at build time. Result is static HTML on a CDN. Best of both worlds for content that doesn't change per-request.

ISR (Incremental Static Regeneration): SSG + on-demand regeneration. Stale-while-revalidate semantics.

Both have SSR's first-paint + SEO benefits but TTFB ≈ CDN edge latency (~50ms globally).

Choosing per page

Modern frameworks (Next.js App Router, Remix, SvelteKit) let you pick per route:

Page typeBest mode
Marketing homepage, blog posts, docsSSG
Product detail (frequent updates)ISR
Search resultsISR (short revalidate) or SSR
Personalized homepage (logged in)SSR
Internal dashboard (logged in)CSR is fine
User profile page (public-ish)SSR or ISR

Hydration — the bridge

SSR + React = HTML arrives ready, then React "hydrates" by attaching listeners and reconciling state. Hydration mismatch = SSR produced different HTML than client would have → React warns and re-renders (visible jank).

Common causes:

  • Date.now() / Math.random() in render.
  • Reading window / localStorage during SSR (won't exist on server).
  • Different user agent / locale assumptions.

React Server Components (RSC) + streaming + selective hydration in Next.js 13+ change this further: only interactive components hydrate; the rest stays server-rendered HTML with zero JS.

Performance comparison

For a typical content page on mid-range mobile, 4G:

ModeTTFBLCPTTI
SSG80ms1.2s2.0s
SSR400ms1.8s2.5s
CSR80ms3.5s4.0s

SSG wins on TTFB + LCP. SSR is close on LCP. CSR is consistently the worst.

Hybrid: the modern pattern

Real apps mix modes:

  • Marketing pages: SSG.
  • App routes: SSR (server-renders the shell, client hydrates).
  • Within the app: client-side navigation between routes (CSR feel).
  • Data fetching: React Query / SWR on the client.

Next.js App Router formalizes this: Server Components render on the server (no JS shipped), Client Components hydrate.

Mental model

SSR/SSG/ISR = render now, optimize first paint and SEO. CSR = render on the client, optimize for snappy in-app navigation after the first load. Most apps benefit from rendering on the server first and behaving like a CSR app after.

Follow-up questions

  • When would you choose CSR over SSR?
  • What is hydration and how does it cause bugs?
  • How does ISR differ from SSR?
  • What changes with React Server Components?

Common mistakes

  • Using CSR for marketing pages — bad SEO, broken social previews.
  • Using SSR for everything when SSG would work — wasted server cost.
  • Hydration mismatch from Date.now/Math.random/window in render.
  • Forgetting metadata (OG, canonical) on SSR pages — fixed automatically with SSG/ISR but easy to miss.
  • Treating SPAs as SEO-friendly because Googlebot 'runs JS' — other crawlers don't.
  • Mixing SSR + SSG inconsistently across the app, confusing users with different perf characteristics.

Performance considerations

  • SSR/SSG move LCP earlier by 1–3s vs CSR for cold visits. The cost is server work (SSR) or build time (SSG). Edge SSR + caching at the edge minimizes the cost. CSR's appeal is dev simplicity; the user-visible cost is real and measurable.

Edge cases

  • Bot user agents (Googlebot) sometimes get a different render path — be careful about cloaking penalties.
  • Auth on SSR: cookies read on the server, but cache strategy must distinguish per-user from public.
  • Edge SSR (Vercel Edge, Cloudflare Workers) reduces TTFB but has limited Node APIs.
  • Streaming SSR delivers HTML in chunks — first byte arrives faster than full render.
  • CSR PWAs with service worker can match SSR's perceived speed on repeat visits.

Real-world examples

  • Most modern frameworks default to SSR/SSG (Next.js, Remix, SvelteKit, Nuxt, Astro).
  • CSR-only apps: Gmail, Figma, Linear — internal-feeling tools where SEO/social previews don't matter.
  • Hybrid: Vercel marketing site (SSG) + Vercel dashboard (CSR after auth).

Senior engineer discussion

Seniors pick rendering mode per route based on audience and freshness, not as a global default. They understand hydration costs and design Server Components / Client Components boundaries thoughtfully. They also know SSR is not free — server cost, complexity, hydration bugs are all real — and they use SSG/ISR wherever possible.

Related questions