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 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
};

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:

  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.

Explore this section

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