Skip to main content
🖥️intermediate

CSR vs SSR vs SSG vs ISR

Modern web apps use four main rendering strategies. Understanding when to use each — Client-Side Rendering, Server-Side Rendering, Static Site Generation, and Incremental Static Regeneration — is key to building fast web apps.

Why Rendering Strategy Matters

How a page is rendered affects:

  • Performance — Time to First Byte (TTFB), First Contentful Paint (FCP)
  • SEO — Can search engines read the content?
  • User experience — Does the page feel fast and interactive?
  • Infrastructure cost — Do you need a server running 24/7?

There are four main strategies, each with trade-offs.

1. Client-Side Rendering (CSR)

The server sends a nearly empty HTML shell. JavaScript downloads, runs in the browser, and renders the page.

hljs html
<!-- What the server sends -->
<!DOCTYPE html>
<html>
  <head><title>My App</title></head>
  <body>
    <div id="root"></div> <!-- empty! -->
    <script src="/bundle.js"></script>
  </body>
</html>
hljs javascript
// React takes over and renders the full page
ReactDOM.createRoot(document.getElementById("root"))
  .render(<App />);

Timeline:

Browser requests page → Server responds: minimal HTML → Browser downloads JS bundle (may be large) → JS executes, renders the page → User sees content → Additional API calls for data

Pros:

  • Simple deployment (serve static files)
  • Fast subsequent navigation (SPA — no full page reload)
  • Great for highly interactive apps
  • Cheap hosting (no server needed)

Cons:

  • Poor SEO (crawlers may not run JS, or run it slowly)
  • Slow initial page load (empty HTML until JS runs)
  • Poor performance on slow networks/devices

Best for: Dashboards, admin tools, apps behind authentication where SEO doesn't matter.

2. Server-Side Rendering (SSR)

For each request, the server renders the full HTML with data and sends it to the browser.

hljs javascript
// Next.js example
export async function getServerSideProps(context) {
  const { params, req } = context;
  const data = await fetchFromDatabase(params.id);

  return {
    props: { data }, // passed to the component
  };
}

export default function Page({ data }) {
  return <div>{data.title}</div>; // HTML rendered on server
}

Timeline:

Browser requests /products/123 → Server fetches data from DB → Server renders HTML with data → Server sends complete HTML → User sees content (fast!) → JS downloads and "hydrates" the page → Page becomes fully interactive

Pros:

  • Excellent SEO (complete HTML sent)
  • Fast First Contentful Paint (user sees real content immediately)
  • Always fresh data
  • Works well for user-specific content

Cons:

  • Requires a server (more infrastructure + cost)
  • Higher Time to First Byte (server must render before responding)
  • Can't be cached as aggressively as static files
  • More complex deployment

Best for: E-commerce product pages, social media feeds, news sites, anything SEO-critical with dynamic per-user or frequently-changing data.

3. Static Site Generation (SSG)

Pages are rendered at build time, not request time. The output is static HTML files that can be served from a CDN.

hljs javascript
// Next.js example
export async function getStaticProps() {
  const posts = await fetchAllBlogPosts();
  return { props: { posts } };
}

export async function getStaticPaths() {
  const posts = await fetchAllBlogPosts();
  return {
    paths: posts.map(p => ({ params: { slug: p.slug } })),
    fallback: false,
  };
}

export default function BlogPost({ post }) {
  return <article>{post.content}</article>;
}

Timeline:

BUILD TIME: All pages rendered → dist/ folder with HTML files REQUEST TIME: Browser requests /blog/my-post → CDN serves pre-built my-post.html (instant! ~1ms) → User sees content immediately → JS hydrates

Pros:

  • Fastest possible page load (CDN-served static HTML)
  • Best SEO
  • Cheapest to host (no server, just CDN)
  • Highly scalable
  • Excellent security (no server to attack)

Cons:

  • Data can become stale (site must be rebuilt for updates)
  • Long build times for large sites (10,000+ pages)
  • Can't serve user-specific content
  • Not suitable for real-time data

Best for: Marketing sites, blogs, documentation, landing pages — anything where content changes infrequently.

4. Incremental Static Regeneration (ISR)

ISR is a Next.js innovation: static pages that automatically regenerate in the background when the content changes. Best of both SSG and SSR.

hljs javascript
// Next.js example — same as SSG but with revalidate
export async function getStaticProps() {
  const post = await fetchPost();
  return {
    props: { post },
    revalidate: 60, // regenerate at most once per 60 seconds
  };
}

Timeline:

First request: serve stale static HTML (instant) trigger background regeneration Second request (after 60s): serve fresh regenerated HTML

Pros:

  • Static file performance (served from CDN)
  • Data can be refreshed without full rebuild
  • Handles content updates gracefully
  • Works with large sites (only regenerate changed pages)

Cons:

  • Slight staleness (content is at most revalidate seconds old)
  • More complex mental model
  • Next.js-specific (though other frameworks are adding similar features)

Best for: Product catalogs, news articles, content that changes periodically but not in real-time.

Choosing the Right Strategy

ScenarioStrategyWhy
Marketing/landing pageSSGNever changes, needs fast load + SEO
Blog postsSSG or ISRMostly static, rare updates
News siteISRFrequent updates but not real-time
E-commerce PDPSSR or ISRSEO + prices/inventory change
User dashboardCSRAuth-required, real-time data, no SEO needed
Social feedSSRUser-specific, real-time
DocumentationSSGStable content, needs SEO
Admin panelCSRBehind auth, rich interactivity

Hybrid Rendering

Modern frameworks let you mix strategies per page:

hljs javascript
// Next.js App Router — choose per component/page

// app/page.js (SSG by default)
export const revalidate = 3600; // ISR: regenerate every hour

// app/products/[id]/page.js (SSR — dynamic data)
export const dynamic = "force-dynamic";

// app/dashboard/page.js (CSR — behind auth)
"use client"; // this and all children render on client
Try it yourself

Key Takeaways

  • CSR: browser renders everything — simple but slow initial load and bad SEO
  • SSR: server renders per request — great SEO and fresh data but needs a server
  • SSG: rendered at build time — fastest load, best for static content
  • ISR: static files that auto-regenerate — combines SSG speed with SSR freshness
  • Most real apps use a mix — static for marketing, SSR for SEO-critical dynamic pages, CSR for dashboards

Ready to test your knowledge?

Take a quiz on what you just learned.

Take the Quiz →