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.
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.
Browser request → Server runs app → HTML with content → Browser paints → JS hydratesTimeline (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.
Browser request → Empty HTML + JS → Download/parse JS → Render → Fetch data → Re-renderTimeline (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 type | Best mode |
|---|---|
| Marketing homepage, blog posts, docs | SSG |
| Product detail (frequent updates) | ISR |
| Search results | ISR (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/localStorageduring 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:
| Mode | TTFB | LCP | TTI |
|---|---|---|---|
| SSG | 80ms | 1.2s | 2.0s |
| SSR | 400ms | 1.8s | 2.5s |
| CSR | 80ms | 3.5s | 4.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).