CSR, SSG, SSR & ISR Rendering Strategies

A rendering strategy is the rule that decides, for a given URL, whether the HTML is produced at build time, on the server per request, on a revalidation schedule, or in the browser. It is the most consequential SEO decision in a JavaScript application because it determines whether content lands in the first wave of Googlebot’s rendering pipeline or waits in the deferred render queue. This guide gives you a per-route framework for choosing among the four modes and sits under the broader prerendering and SSR strategies section.

Prerequisites

  • A meta-framework that supports per-route rendering (Next.js, Nuxt 3, SvelteKit, Remix/React Router 7) or a build pipeline that can prerender routes.
  • A route inventory: a list of every public URL pattern and the data each depends on.
  • Search Console access to measure time-to-index before and after changing a route’s mode.
  • A baseline of which routes currently earn organic traffic, so you prioritize the highest-value pages.

The decision: two axes

Map each route against two questions — how fresh must the data be? and how important is this route for organic search? Those axes point you at a rendering mode.

Rendering-mode decision matrix A two-axis matrix plotting data freshness need against SEO importance, placing SSG, ISR, SSR, and CSR in the appropriate quadrants. SEO importance ↑ Data freshness need → SSG High SEO, stable data Docs, marketing, landing SSR / ISR High SEO, changing data Products, listings, news SSG + light JS Low SEO, stable data About, internal tools CSR Low SEO, live data Dashboards, app shell
Map each route by how fresh its data must be and how much it needs to rank, then pick the mode for that quadrant.

How it breaks

The most common failure is treating rendering as a global setting. A team ships an entire storefront as a single-page app because the dashboard needed to be interactive, and the product pages — the routes that actually earn search traffic — inherit CSR and get indexed as empty shells. The symptom in Search Console is Crawled — currently not indexed on high-value URLs, or a rendered-HTML snapshot that shows only the loading skeleton.

<!-- ❌ Product page shipped as CSR: crawler sees no product data in the first wave -->
<div id="root"></div>
<script src="/bundle.js" defer></script>

Step-by-step fix

  1. Inventory routes by data freshness. Tag each route static, periodic, or live. Anything static is an SSG candidate; periodic maps to ISR; live maps to SSR or CSR.

  2. Set the per-route mode. In Next.js App Router, the fetch cache and revalidate express the mode:

    // app/products/[id]/page.jsx
    export const revalidate = 0;        // SSR: always fresh, rendered per request
    // export const revalidate = 3600;  // ISR: regenerate at most hourly
    // export const dynamic = 'force-static'; // SSG: build once

    The same intent in Nuxt 3 is expressed through route rules:

    // nuxt.config.ts
    export default defineNuxtConfig({
      routeRules: {
        '/':            { prerender: true },              // SSG
        '/blog/**':     { isr: 3600 },                    // ISR
        '/products/**': { ssr: true },                    // SSR
        '/app/**':      { ssr: false },                   // CSR island
      },
    });
  3. Confirm content is in the response. For every route you changed, curl the URL and grep for the primary heading or price. If it is absent, the mode is not actually applying.

  4. Keep metadata aligned with the mode. Whatever mode you choose, titles, canonicals, and structured data must render in the same pass — coordinate with dynamic metadata management so the <head> is never left to a later client update.

Gotchas & edge cases

  • SSG with stale data. A statically generated price that changes daily will mismatch the live page; use ISR with a short revalidate window instead of full SSG.
  • SSR personalization leaking into the cache. Rendering user-specific content on a cacheable SSR route can serve one user’s data to others or to the crawler. Keep personalized fragments client-side.
  • CSR fallbacks that never fire for bots. A <noscript> fallback is not a substitute for indexable content; crawlers execute JavaScript and ignore most <noscript> shells.
  • Choosing CSR for “speed.” CSR lowers TTFB but pushes Largest Contentful Paint to the client, often hurting Core Web Vitals more than SSR’s higher TTFB would.

Validation checklist

Performance & crawl-budget notes

Moving SEO-critical routes off CSR removes them from the render queue, so they index in the first wave and stop consuming the JavaScript execution budget on every change. On large catalogs this is the difference between hours-to-index and weeks-to-index, and it frees render capacity for the genuinely dynamic routes that still need it. Track the impact through crawl-budget signals.

Go deeper

Frequently Asked Questions

Can I mix rendering strategies in one application? Yes. Meta-frameworks like Next.js, Nuxt, and SvelteKit let you set the rendering mode per route or per page. A typical app statically generates marketing pages, server-renders inventory pages, incrementally regenerates blog content, and leaves authenticated areas client-rendered.

Which rendering mode is best for SEO? Any mode that puts your primary content in the initial HTML response is good for SEO — SSG, SSR, and ISR all qualify. Pure CSR is the only mode that defers content to the rendering queue, so reserve it for routes that do not need to rank.

← Back to Prerendering & SSR Strategies