Search…

Rendering strategies: CSR, SSR, SSG, ISR

In this series (12 parts)
  1. What frontend system design covers
  2. Rendering strategies: CSR, SSR, SSG, ISR
  3. Performance fundamentals: Core Web Vitals
  4. Loading performance and resource optimization
  5. State management at scale
  6. Component architecture and design systems
  7. Client-side caching and offline support
  8. Real-time on the frontend
  9. Frontend security
  10. Scalability for frontend systems
  11. Accessibility as a system design concern
  12. Monitoring and observability for frontends

Every web page reaches the user through a rendering strategy. The strategy determines where HTML is generated, when it is generated, and how much work the browser must do before the user sees content. Pick wrong and you get slow loads, poor SEO, or infrastructure costs that scale linearly with traffic.

This article covers four strategies: client-side rendering, server-side rendering, static site generation, and incremental static regeneration. Each solves a real problem and creates new ones. As discussed in frontend system design fundamentals, trade-off awareness is what separates good architecture from default choices.

Client-side rendering (CSR)

CSR ships an empty HTML shell and a JavaScript bundle. The browser downloads the JS, executes it, fetches data from APIs, then renders the page. Everything happens on the client.

sequenceDiagram
  participant Browser
  participant CDN
  participant API

  Browser->>CDN: GET /page
  CDN->>Browser: HTML shell + JS bundle
  Browser->>Browser: Parse and execute JS
  Browser->>API: Fetch data
  API-->>Browser: JSON response
  Browser->>Browser: Render DOM with data
  Note over Browser: Page is now interactive

Client-side rendering sequence. The browser receives a near-empty HTML document and builds the entire page with JavaScript.

When CSR works well

CSR shines for applications behind authentication where SEO does not matter. Dashboards, admin panels, internal tools; these benefit from CSR because:

  • Simple infrastructure. You serve static files from a CDN. No server-side computation per request.
  • Rich interactions. Single-page application routing feels instant after the initial load.
  • Easy deployment. Build once, deploy to any static host.

When CSR breaks down

CSR has a fundamental problem: the user stares at a blank page while JavaScript downloads and executes. On a fast connection with a modern device, this takes 1 to 2 seconds. On a slow connection with a budget phone, it can take 8 to 12 seconds.

Search engines have improved at indexing JavaScript-rendered content, but it remains unreliable. Critical landing pages, product pages, and blog posts should not depend on CSR alone.

The JavaScript bundle is also a scaling problem. As your application grows, the bundle grows. Without aggressive code splitting, users download megabytes of code they may never execute.

Server-side rendering (SSR)

SSR generates the full HTML on the server for each request. The browser receives a complete page that it can display immediately. JavaScript then “hydrates” the page, attaching event listeners and making it interactive.

sequenceDiagram
  participant Browser
  participant Server
  participant Database

  Browser->>Server: GET /page
  Server->>Database: Query data
  Database-->>Server: Data response
  Server->>Server: Render HTML with data
  Server->>Browser: Complete HTML + JS bundle
  Browser->>Browser: Display HTML immediately
  Browser->>Browser: Hydrate (attach event listeners)
  Note over Browser: Page is now interactive

Server-side rendering sequence. The server does the heavy lifting, sending a fully rendered page to the browser.

The hydration problem

SSR creates a paradox. The user sees content quickly (good TTFB, good LCP), but the page is not interactive until hydration completes. This gap, called the “uncanny valley,” means users see buttons they cannot click and forms they cannot fill.

Hydration is expensive. The browser must:

  1. Download the JavaScript bundle.
  2. Parse and execute it.
  3. Reconcile the server-rendered DOM with what React (or your framework) expects.
  4. Attach all event listeners.

For large pages, hydration can take several seconds. The user sees content but cannot interact with it. This is often worse than a loading spinner because it violates expectations.

Modern frameworks address this with selective hydration, streaming SSR, and React Server Components. These techniques allow the server to send HTML in chunks and the browser to hydrate components progressively rather than all at once.

SSR trade-offs

The server computes HTML for every request. This means:

  • Higher server costs. Each page view triggers server-side rendering. Traffic spikes require scaling compute, not just bandwidth.
  • Slower TTFB under load. If the server is busy, response times increase for everyone.
  • Complexity. Your code must run in both Node.js and the browser. Environment-specific bugs are common.

Static site generation (SSG)

SSG generates all pages at build time. The output is plain HTML files that can be served from a CDN with zero server-side computation.

sequenceDiagram
  participant Build as Build Process
  participant CMS
  participant CDN
  participant Browser

  Build->>CMS: Fetch all content
  CMS-->>Build: Content data
  Build->>Build: Generate HTML for every page
  Build->>CDN: Deploy static HTML files
  Note over CDN: Files cached at edge
  Browser->>CDN: GET /page
  CDN->>Browser: Pre-built HTML
  Browser->>Browser: Display immediately
  Browser->>Browser: Hydrate if needed

Static site generation sequence. Pages are built once and served as static files from a CDN.

SSG advantages

SSG produces the fastest possible page loads. The HTML is pre-built and cached at CDN edge nodes worldwide. TTFB is typically under 50ms regardless of where the user is located.

Security is also simpler. There is no server to hack, no database to inject, no runtime to exploit. The attack surface shrinks to the CDN and any client-side JavaScript.

SSG limitations

The critical limitation is build time. If your site has 100,000 pages and each takes 200ms to build, a full rebuild takes over 5 hours. Content changes are not visible until the next build completes.

SSG is ideal for content that changes infrequently: documentation, blogs, marketing sites. It breaks down for pages that need real-time data or user-specific content.

Incremental static regeneration (ISR)

ISR combines the performance of SSG with the freshness of SSR. Pages are statically generated but can be revalidated in the background after a configurable time interval.

sequenceDiagram
  participant Browser
  participant CDN
  participant Server
  participant Database

  Browser->>CDN: GET /page
  CDN->>Browser: Cached HTML (stale)
  Note over CDN: Revalidation triggered in background
  CDN->>Server: Rebuild this page
  Server->>Database: Fetch fresh data
  Database-->>Server: Updated data
  Server->>Server: Generate new HTML
  Server->>CDN: Updated HTML
  Note over CDN: Next request gets fresh page

ISR sequence. The user gets the cached version immediately while a fresh version is generated in the background.

ISR uses a stale-while-revalidate pattern. The first user after the revalidation window gets the stale page (still fast) and triggers a background rebuild. The next user gets the fresh page.

This works well for product pages, news articles, and any content that changes periodically but does not need to be real-time. You get CDN-level performance with data that is at most N seconds old, where N is your revalidation interval.

ISR trade-offs

ISR requires a serverless or server environment to handle background regeneration. It is not purely static hosting. The revalidation logic adds complexity, and debugging stale content issues requires understanding the caching layer.

Comparing the strategies

The numbers above are representative for a typical content page on a 4G connection. Actual values vary based on page complexity, server location, and device capability.

StrategyBest forSEOTTFBDynamic dataInfrastructure
CSRApps behind authPoorSlowYesStatic CDN
SSRPersonalized pagesGoodMediumYesServer required
SSGContent sitesExcellentFastNoStatic CDN
ISRPeriodically updated contentExcellentFastPartialServerless + CDN

Hybrid approaches

Real applications rarely use a single strategy. A typical e-commerce site might use:

  • SSG for the homepage and category pages (high traffic, infrequent changes).
  • ISR for product pages (frequent inventory updates, still cacheable).
  • SSR for the search results page (user-specific, cannot be pre-built).
  • CSR for the shopping cart and checkout (behind auth, highly interactive).

Modern frameworks like Next.js, Nuxt, and Astro support per-route rendering strategies. This is a powerful capability. The key is matching each route to the strategy that fits its constraints rather than applying one strategy globally.

graph TD
  subgraph E-commerce Site
      HP[Homepage - SSG] --> CAT[Category Pages - SSG]
      CAT --> PDP[Product Pages - ISR]
      PDP --> SEARCH[Search Results - SSR]
      PDP --> CART[Cart - CSR]
      CART --> CHECKOUT[Checkout - CSR]
  end

  style HP fill:#d4edda
  style CAT fill:#d4edda
  style PDP fill:#fff3cd
  style SEARCH fill:#cce5ff
  style CART fill:#f8d7da
  style CHECKOUT fill:#f8d7da

Hybrid rendering in an e-commerce application. Each route uses the strategy that matches its requirements.

Streaming and partial hydration

The next evolution in rendering is not a new strategy but a refinement of SSR. Streaming SSR sends HTML to the browser in chunks as each component finishes rendering on the server. The browser starts painting immediately instead of waiting for the entire page.

Partial hydration takes this further by only hydrating the interactive parts of the page. A static heading does not need event listeners. A navigation menu does. By hydrating selectively, you reduce the JavaScript the browser must process.

React Server Components represent this direction. Server components run only on the server, send their output as serialized data, and never ship their code to the client. Client components handle interactivity. The boundary between them is explicit in the code.

What comes next

Choosing a rendering strategy determines when users see content. But how fast is fast enough? Core Web Vitals defines the metrics that quantify frontend performance, how to measure them accurately, and what targets to aim for.

Start typing to search across all content
navigate Enter open Esc close