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.
What to gather before mapping routes to rendering modes Four prerequisites — a per-route framework, a route inventory, Search Console access, and a traffic baseline — combine into readiness to assign a rendering mode per route. Four inputs make a route ready to be assigned a mode Per-route framework Next.js · Nuxt 3 · SvelteKit Route inventory every URL and the data it needs Search Console access measure time-to-index before and after Traffic baseline prioritise the highest-value pages Ready to assign a rendering mode per route
Assemble a per-route framework, a route inventory, Search Console access, and a traffic baseline before deciding how each URL should render.

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>
How one global CSR setting breaks product pages A single app-wide CSR decision cascades: the dashboard is fine, but product routes inherit CSR, ship an empty shell, and end up crawled but not indexed. How one global setting breaks product pages Rendering chosen app-wide: CSR one setting for every route Dashboard routes no ranking needed — CSR is fine Product routes must rank — inherit CSR anyway Crawler sees <div id=root> no product data in the first wave GSC: Crawled — not indexed
Treating rendering as a global switch lets high-value product routes inherit CSR and land in Search Console as crawled but not indexed.

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.

The four-step per-route rendering fix Inventory each route by data freshness, set its per-route mode, confirm the content is in the response, then keep metadata rendering in the same pass. Assign the mode, then prove content is in the response 1 Inventory static / periodic / live 2 Set the mode revalidate / route rules 3 Confirm curl for heading / price 4 Align meta title · canonical · JSON-LD Every SEO-critical route ends with its content and metadata in the first response
Work each route through the same four steps so its content and metadata land in the initial response, not 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.
Four rendering-mode traps and what each one costs Static generation of volatile data, personalised SSR in a shared cache, relying on noscript, and choosing CSR for speed each map to a specific SEO or correctness failure. Each edge case has a specific cost The trap What it costs SSG for daily-changing prices indexed price mismatches the live page Personalised SSR on a cached route one user's data served to bots and others noscript as the crawlable fallback crawlers run JS and ignore the shell Choosing CSR for lower TTFB LCP moves to the client, worse vitals
Every rendering-mode shortcut carries a distinct penalty — a stale index, leaked data, an ignored fallback, or degraded vitals.

Validation checklist

The pre-ship validation gate for a route's rendering mode Five checks — a documented mode, content without JavaScript, matching rendered HTML, no LCP regression, and short ISR windows — must all pass before a route indexes in the first wave. Five checks gate a route before it ships Every public route has a documented mode curl shows primary content without JavaScript GSC rendered HTML matches the live page Lighthouse shows no LCP regression ISR windows short enough to avoid a stale index Indexes in the first wave
Only when all five checks pass does a route reliably land in Googlebot's first wave instead of the deferred render queue.

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.

Time to index: render queue versus first wave Content deferred to the render queue on CSR routes can take days to weeks to index, while content in the first response indexes in minutes to hours. Time to index: render queue versus first wave CSR render queue days to weeks SSG / SSR / ISR first wave min–hours longer to index →
Moving SEO-critical routes out of the render queue and into the first response collapses time-to-index from weeks to hours on large catalogs.

Go deeper

Two deeper guides that build on the rendering-mode framework From this per-route framework, one path is a head-to-head decision checklist for choosing a mode, and the other compares hydration strategies once you render on the server. Where to go next Rendering-mode framework this guide Choosing between the four modes a head-to-head decision checklist Hydration strategies compared full · partial · streaming
Once the framework assigns each route a mode, drill into the mode-choice checklist or into how server-rendered routes should hydrate.

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