Prerendering and SSR Strategies for SPAs

Client-side rendering moves HTML construction into the browser, which means a search engine sees meaningful content only after it has downloaded your bundle, executed it, and waited for the framework to paint. That dependency is the single largest source of indexing risk for JavaScript applications — and the entire point of a rendering strategy is to decide where and when your HTML is produced so that a crawler never has to gamble on your JavaScript running successfully. This section is the decision layer that sits on top of the crawling and rendering fundamentals: once you understand how Googlebot’s two-wave rendering pipeline works, the next question is which rendering mode keeps your routes out of the slow, fragile second wave.

The choice is rarely all-or-nothing. Modern frameworks let you mix static generation, server rendering, incremental revalidation, and pure client rendering on a per-route basis. A marketing page can be statically generated, a product page server-rendered, a pricing table incrementally revalidated, and an authenticated dashboard left as a client-rendered island — all in the same application. Getting that mix right is what separates an app that indexes completely from one that leaks organic traffic on every deploy.

The rendering spectrum: where your HTML comes from

Every rendering strategy answers one question — at what moment is the HTML for this URL produced? — and the answer determines whether a crawler sees content in the raw response or has to render JavaScript to find it.

The rendering spectrum from build time to client runtime A horizontal axis showing when HTML is produced for SSG, ISR, SSR, and CSR, and whether a crawler sees populated HTML without executing JavaScript. Build time Request time Client runtime SSG HTML built once Crawler-ready ISR Built + revalidated Crawler-ready SSR HTML per request Crawler-ready CSR HTML in browser Needs JS to render Filled = content is present in the first-wave HTML Hollow = content only appears after the second-wave render
The rendering spectrum: the earlier HTML is produced, the less a crawler depends on executing your JavaScript.

Static Site Generation (SSG) produces HTML at build time and serves it from a CDN. It has the lowest Time to First Byte and the strongest crawl guarantee, but it cannot reflect data that changes between builds. Server-Side Rendering (SSR) generates HTML on every request, so content is always fresh and fully present in the response, at the cost of server compute and a higher TTFB. Incremental Static Regeneration (ISR) is the middle ground: pages are served statically but regenerated in the background on a revalidation interval or on demand. Client-Side Rendering (CSR) ships an empty shell and builds the DOM in the browser — the fastest to deploy and the only option for highly personalized views, but the one that puts your indexability at the mercy of the rendering queue. Each guide below drills into one band of this spectrum; start with the rendering-strategy decision guide to map your routes onto it.

Core failure modes

Choosing a strategy is only half the work; most lost traffic comes from a handful of recurring implementation failures.

The most common of them, the empty-shell index, is a chain of events that all trace back to depending on the second-wave render.

How a pure CSR route ends up indexed as an empty shell A sequence from fetch to an empty shell to the render queue to a JavaScript failure to a blank index entry. Crawl fetch first wave Empty shell div id=root only Render queue second wave, delayed JS errors or times out Indexed blank no content ranked any break in the second wave leaves the shell as the indexed document
The empty-shell index: when the second-wave render never completes, the bare shell is what gets indexed.
  • The empty-shell index. A pure CSR route is fetched, the crawler queues it for rendering, and either the bundle errors, a data request hangs past the execution budget, or a route guard blocks render — so the page is indexed as the bare <div id="root">. This is the canonical CSR failure and the reason Google indexes blank pages for React apps.
  • Hydration mismatch wiping content. Server-rendered HTML and the client’s first render disagree, React or Vue discards the server markup, and during the swap the document can briefly lose content and structured data. The fix lives in the React hydration mismatch workflow.
  • Cloaking through dynamic rendering. Serving a prerendered snapshot to bots and a different client app to users drifts over time until the two diverge enough to look like cloaking. Dynamic rendering is now a fallback, not a destination.
  • Stale ISR snapshots. A revalidation interval set too long means crawlers keep seeing outdated prices, titles, or canonical tags, creating a mismatch between what is indexed and what users see.
  • Streaming that defers the <head>. Streaming SSR flushes the body progressively, but if metadata resolves in a late chunk, the crawler may snapshot the document before titles and canonical tags arrive.

Implementation patterns

The framework-agnostic pattern is to make rendering a per-route decision driven by how dynamic and how SEO-critical each route is. The pseudo-config below expresses that intent independent of any one framework:

// Route-level rendering policy — the shape every meta-framework encodes
export const routePolicy = {
  '/':                 { mode: 'ssg' },                       // marketing: build once
  '/blog/:slug':       { mode: 'isr', revalidate: 3600 },     // content: refresh hourly
  '/products/:id':     { mode: 'ssr' },                       // inventory: always fresh
  '/app/*':            { mode: 'csr' },                        // authenticated: no SEO need
};

Read as a flowchart, that same policy is just three questions asked in order — SEO need first, then freshness, then whether the content changes between builds.

A decision tree mapping a route to its rendering mode Starting from whether a route is SEO-critical, the tree branches on per-request freshness and build-time change to choose CSR, SSR, SSG, or ISR. SEO-critical? Fresh per request? Changes between builds? CSR — no SEO need authenticated views SSR — HTML per request always fresh SSG — built once ISR — built + revalidated no yes yes no no yes
The same routing intent as the policy object above, drawn as a decision: only non-SEO routes stay on CSR, and freshness needs pick between SSR, ISR, and SSG.

For routes that must stay client-rendered but still need to be indexed, prerendering bridges the gap: a headless browser renders each public route at build or request time and the resulting HTML is cached and served to crawlers. The dynamic rendering and bot prerendering cluster covers the build-time and middleware variants, including how to set up prerendering for a React SPA.

When you do render on the server, streaming and partial hydration keep the performance cost down. Streaming SSR flushes the shell immediately and resolves data-dependent chunks as they become ready, while islands/partial hydration ship JavaScript only for interactive regions. Both are covered in incremental and streaming SSR for SEO.

Verification & observability

A rendering strategy is only correct if you can prove a crawler sees populated HTML. The verification loop is consistent across strategies:

The four-step verification loop for any rendering strategy A repeating loop: curl the raw response, inspect the crawled page in Search Console, reload with JavaScript disabled, and track LCP and CLS in field data. Prove a crawler sees populated HTML — then keep proving it curl the raw response is primary content in first-wave HTML? GSC View Crawled Page does the render match what users see? disable JS and reload SSG/SSR still show, CSR goes blank track LCP and CLS field data, watch hydration shift
The same four-step loop verifies any strategy: raw response, crawled render, JS-disabled reload, then field-data vitals.
  1. curl the raw response. curl -sL https://example.com/route | grep -o '<h1>.*</h1>' confirms whether your primary content is in the first-wave HTML before any JavaScript runs.
  2. GSC URL Inspection → View Crawled Page. Compare the rendered HTML and the screenshot against what users see; a divergence is a cloaking or hydration signal. This is the backbone of the SEO audit workflows.
  3. Disable JavaScript in DevTools and reload. SSG/SSR/ISR routes still show content; a CSR route goes blank — which tells you immediately whether the route depends on the second wave.
  4. Track LCP and CLS in field data. Hydration-heavy pages frequently regress Cumulative Layout Shift, so watch layout shift during hydration.

Crawl-budget and indexing impact

Rendering strategy directly governs crawl economics. Server-rendered and static routes are indexed in the first wave, often within hours, because no rendering-queue slot is required. Pure CSR routes wait for the second wave, which can lag from days to weeks on large or low-authority sites, and every wasted render consumes the execution budget described in JavaScript execution limits and crawl budget. On a site with tens of thousands of URLs, moving high-value routes from CSR to SSG or SSR can compress time-to-index from weeks to hours and reclaim render budget for genuinely dynamic pages. The inverse is just as real: leaving money-pages on CSR means they re-enter the queue on every content change and may never catch up.

The backlog slider shows why a CSR route’s content can lag its crawl by days, while a prerendered route is indexed immediately.

Explore this section

The three guides that make up this rendering-strategy section This section branches into three guides: choosing a rendering mode per route, prerendering for bots, and incremental and streaming SSR. Rendering strategy CSR, SSG, SSR & ISR strategies map each route to a mode Dynamic rendering and bot prerendering serve crawlers rendered HTML Incremental and streaming SSR stream the shell, hydrate in parts
This section fans out into three guides, from choosing a per-route mode to prerendering and streaming SSR.

Frequently Asked Questions

Is client-side rendering bad for SEO? Not inherently. Googlebot renders JavaScript, so a correctly built CSR app can rank. The risk is operational: rendering is deferred to a queue, execution is capped at a few seconds, and any route whose content depends on JavaScript that fails, times out, or arrives late may be indexed empty. Prerendering or server rendering removes that dependency for the routes that need to rank.

What is the difference between SSR, SSG, and ISR? SSG generates HTML once at build time, SSR generates it per request on the server, and ISR generates it at build but revalidates and regenerates individual pages on a schedule or on demand. All three deliver populated HTML in the initial response, which is what crawlers index in the first wave.

Does Google still support dynamic rendering? Google now describes dynamic rendering as a workaround rather than a recommended long-term solution. It still works, but server-side rendering, static generation, or hydration-based approaches are preferred because they serve the same HTML to users and bots and avoid cloaking risk.

← Back to client-side-rendered.com