What is Client-Side Rendering (CSR)?
Client-Side Rendering (CSR) is a web architecture pattern where the browser builds the page's HTML using JavaScript after the initial page load.
What is Client-Side Rendering (CSR)?
Client-Side Rendering (CSR) is a web architecture pattern where the browser downloads a minimal HTML shell, fetches JavaScript bundles, and then constructs the full page DOM on the client. The server's role is limited to serving static assets — it doesn't produce per-request HTML. React (introduced in 2013) popularized this model, and Create React App made it the default until its deprecation in early 2025. CSR means the browser does the heavy lifting: parsing JS, fetching data via API calls, and rendering the UI. The first meaningful paint depends entirely on bundle size and client device speed. Lighthouse scores for pure CSR apps routinely land below 50 on performance for content-heavy pages. CSR still makes strong sense for authenticated dashboards and internal tools where SEO and initial load speed aren't critical — think admin panels, analytics dashboards, or any app behind a login wall.
How it works
A typical CSR flow:
- Browser requests a URL. The server returns a near-empty HTML file — usually just a
<div id="root"></div>and a<script>tag. - JavaScript downloads and executes. The browser fetches the app's JS bundle (often 200KB–2MB gzipped for production SPAs).
- Client-side router takes over. Libraries like React Router or TanStack Router match the URL to a component tree.
- Data fetching happens in the browser. Components fire off
fetch()or use something like TanStack Query to hit REST/GraphQL APIs. - DOM is built. React, Vue, or Svelte diffs a virtual (or compiled) representation and writes real DOM nodes.
- Subsequent navigations are instant. Since the full app is already loaded, route changes swap components without a server round-trip.
Here's the minimal HTML a CSR app serves:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>My App</title>
<link rel="stylesheet" href="/assets/index.css" />
</head>
<body>
<div id="root"></div>
<script type="module" src="/assets/index.js"></script>
</body>
</html>
Every pixel the user sees is painted by JavaScript. That's the defining trait — and the core trade-off. Search engine crawlers like Googlebot can execute JS, but there's a rendering budget and a delay (often seconds). Other crawlers (Bing, social media link previews) are less reliable with JS execution. This is why CSR and SEO have always been in tension.
When to use it
CSR is the right call in specific situations, and the wrong call in others. We've shipped this on 50+ projects and the pattern is clear:
Use CSR when:
- The app lives behind authentication (dashboards, SaaS tools, admin panels)
- SEO doesn't matter for the routes in question
- You want rich interactivity with instant client-side transitions
- Your team is small and you want to skip server infrastructure — just deploy to a CDN
- Offline-first PWAs where the service worker caches the shell
Avoid CSR when:
- You need organic search traffic (marketing sites, blogs, e-commerce PDPs)
- Core Web Vitals matter for ranking — CSR typically inflates LCP and increases CLS
- Your audience is on low-powered devices or slow networks
- You need link preview cards on social platforms (they won't execute your JS)
Our preferred stack is Next.js or Astro precisely because they let us mix rendering strategies per route. Pure CSR across an entire site is rarely the answer in 2026.
Client-Side Rendering vs alternatives
| CSR | SSR (Server-Side Rendering) | SSG (Static Site Generation) | Streaming SSR | |
|---|---|---|---|---|
| HTML generated | In the browser | On the server per request | At build time | On the server, streamed in chunks |
| Time to First Byte | Fast (static shell) | Slower (server compute) | Fastest (pre-built) | Moderate (first chunk fast) |
| LCP | Slow (JS-dependent) | Fast | Fastest | Fast |
| SEO | Poor without workarounds | Excellent | Excellent | Excellent |
| Interactivity | Full after JS loads | Needs hydration | Needs hydration | Progressive hydration possible |
| Infrastructure | CDN only | Node.js server or edge runtime | CDN only | Node.js server or edge runtime |
The modern trend is hybrid: use SSR or SSG for public-facing pages and CSR for authenticated, interactive sections. Next.js App Router (stable since v13.4, May 2023) and Astro's client directives (client:load, client:idle) both make this mixing trivial.
Real-world example
We built an internal reporting dashboard for a logistics client using Vite 6 + React 19 as a pure CSR app. The entire build output was static files deployed to Cloudflare Pages — no server, no Lambda, no containers. Bundle size landed at 187KB gzipped. Behind the login wall, SEO was irrelevant, so CSR was the simplest architecture. TanStack Query handled data fetching with a 30-second stale time. Page transitions felt instant because the router swapped components without network requests for HTML. The total infrastructure cost: $0/month on the free tier. If this had been a public-facing marketing site, we'd have gone with Astro or Next.js with SSR — but for this use case, CSR was the pragmatic choice.