← Back to Studio Notes

Server-Side Rendering (SSR) vs Single-Page Apps (SPA) for SEO

Understand the differences between SSR and SPA architecture. Learn how rendering choices impact Google indexing, Core Web Vitals, and user experience.

KEHEM / Studio Notes
  KEHEM

When building a web platform, deciding how your HTML is rendered determines your search engine rankings and initial page load speed.

If you choose a pure Client-Side SPA for a content-heavy business website, Googlebot may see an empty <div id="app"></div> tag, leading to delayed indexing and poor organic traffic.

Here is a clear guide on when to use Server-Side Rendering (SSR) vs. Single-Page Applications (SPA).

Comparison Matrix: SSR vs SPA

MetricServer-Side Rendering (SSR / Nuxt)Single-Page App (SPA / Vanilla Vue)
SEO & Google Indexing⭐⭐⭐⭐⭐ Instant, perfect crawlability⭐⭐ Delayed / JavaScript render queue
First Contentful Paint⭐⭐⭐⭐⭐ Sub-second HTML delivery⭐⭐ Waits for JS bundle download
Social OpenGraph Previews⭐⭐⭐⭐⭐ Dynamic meta tags per URL⭐ Requires SSR or prerender proxy
Server Cost / Overhead⭐⭐⭐ Requires Node/Server runtime⭐⭐⭐⭐⭐ Cheap static hosting (CDN/S3)
App-Like Interactivity⭐⭐⭐⭐ Smooth after hydration⭐⭐⭐⭐⭐ Instant client navigation

How Google Actually Handles JavaScript in 2026

The old advice — "Google can't read SPAs" — is out of date, and the current reality is more awkward than either side of the argument admits.

Google processes JavaScript in a two-wave indexing model: it crawls the raw HTML first, then queues the page for rendering in a headless Chromium instance. That second wave is a genuine queue, not an instant follow-up. In practice, rendered content on JavaScript-dependent pages can take days or weeks to be indexed, while server-rendered HTML is indexed in the first pass. For a new site competing for rankings, that delay compounds: slower indexing means slower learning about which pages deserve to rank.

Three consequences most teams do not plan for:

Rendering is not the only crawler behaviour that matters. Social platforms (Facebook, LinkedIn, X), messaging apps used for link sharing (Slack, WhatsApp, Teams) and most AI crawlers (GPTBot, ClaudeBot, PerplexityBot and similar) largely do not execute JavaScript. If your product pages or articles render client-side, your links appear as bare URLs with no preview, and you are invisible in the AI answer engines that increasingly drive discovery.

Hydration is not free. An SSR page that ships a large JavaScript bundle and re-renders everything on the client can post excellent lab scores and still feel sluggish. Interaction-to-Next-Paint (INP) — a Core Web Vital since 2024 — punishes long hydration tasks specifically, which is why the metric improved for many sites after they moved from heavy client-side rendering to server rendering with islands.

Lab performance is not field performance. Lighthouse on a fast laptop is a diagnostic, not a reality check. What affects rankings is field data from CrUX: real users, real devices, often mid-range Android phones on mobile networks. Check the field data for your own URLs in PageSpeed Insights and Search Console before believing any report about your own site.

The Render Modes, Ranked by Effort

Nuxt gives you more than two options, and choosing per route is usually the right answer:

ModeHow it worksBest forTrade-off
SSG (static generation)HTML built at deploy timeMarketing pages, blogs, docsRebuild required for content changes
ISR / SWR (incremental)Static HTML, regenerated in the backgroundLarge content sites, cataloguesSlightly stale first view
SSR (per request)HTML rendered on each requestPersonalised pages, pricing by regionServer cost and latency
CSR / SPAShell + client-side data fetchAuthenticated app dashboardsPoor SEO, slower first paint
Streaming SSRHTML sent progressively as it rendersLong pages with slow data sourcesMore complex error handling

The Modern Hybrid Solution: Nuxt 3 Route Rules

In 2026, you no longer have to pick just one. With Nuxt 3, you can apply hybrid rendering per route:

  • /blog/** → Static Site Generation (SSG): Pre-rendered HTML cached at the CDN edge for maximum SEO.
  • /pricing → Server-Side Rendered (SSR): Dynamic currency switching per user geo-location.
  • /app/** → Single-Page App (SPA): Rich, authenticated dashboard behind a login screen.
// nuxt.config.ts
export default defineNuxtConfig({
  routeRules: {
    '/blog/**': { prerender: true },              // SSG at build time
    '/pricing': { swr: 3600 },                    // SSR, cached for an hour
    '/app/**': { ssr: false },                    // pure client-side
    '/api/**': { cors: true },
  },
})

The most valuable line in that configuration is often swr. Caching an SSR page for an hour gives you the SEO and first-paint benefits of server rendering with the load characteristics of a static page — which removes the usual objection that SSR is too expensive to run at traffic.

What You Must Get Right in SSR

Server rendering handles the HTML; it does not handle the SEO details that decide rankings. Non-negotiables:

  • Unique <title> and meta description per route, generated from the page's own data, not a template default.
  • A correct canonical tag per page, and consistent trailing-slash behaviour. Duplicate URLs split your authority.
  • Structured data (JSON-LD) for articles, products, FAQs and breadcrumbs.
  • OpenGraph and Twitter card tags written server-side so link previews are correct at the moment of sharing.
  • hreflang tags for multi-language or multi-region sites, pointing to real, indexable URLs.
  • A sitemap generated from real routes, updated on content changes, and a robots.txt that does not accidentally block rendering assets.
  • Text content present in the HTML, not injected after load. If your headline arrives via a client fetch, you have defeated the purpose.

Also watch for hydration mismatches — the classic causes are rendering dates and times, reading localStorage or window during SSR, and random IDs. These produce flickering content and console errors, and they occasionally produce worse: two different versions of the page, one for the crawler and one for the user.

When a Pure SPA Is Still the Right Call

Server rendering is not a universal good. A pure client-side app remains correct for:

  • Authenticated dashboards where no crawler needs the content and every page is user-specific.
  • Internal tools with a known, logged-in audience.
  • Highly interactive applications — editors, canvases, real-time collaboration — where the initial render cost is irrelevant because the user will spend an hour inside.
  • Products behind a paywall or login wall, where search discovery happens on marketing pages instead.

The rule of thumb: if a URL should be findable, shareable or previewable, render it on the server. If it should only be reachable by a logged-in user, client-side rendering costs you nothing.

Cost and Infrastructure Reality

SSG is the cheapest option by a wide margin: static files on a CDN, with essentially no per-request compute. Serving a static blog to 500,000 monthly readers costs a few dollars.

SSR moves the cost into a Node runtime that must handle concurrency. Two mitigations keep it affordable: cache aggressively at the route level (SWR/ISR), and put a CDN in front so repeat visits never touch the origin. A well-cached hybrid Nuxt deployment will typically run comfortably on a modest VPS for a site in the hundreds of thousands of monthly visits.

The pattern we see fail is an SSR app with caching disabled and a database query in every page render. That is not an argument against SSR — it is an argument against un-cached origin work, and it is fixable in an afternoon.

A Migration Lesson Worth the Length

We moved a client's content section from a pure SPA to prerendered routes. Indexed pages went from a fraction of published articles to nearly all of them, and — more telling than the ranking change — their average time-to-index for a new article fell from roughly three weeks to two days. Their editorial team noticed before their SEO dashboard did, because new posts started showing up in search within the week they were written.

No content changed. No links were built. The rendering model was the entire difference.

Measuring Your Own Rendering (A Practical Checklist)

Do this before changing anything. It takes an hour and prevents expensive guesses:

  1. Check indexed page counts. Search Console → Pages → "Indexed" versus the number of URLs in your sitemap. A large gap is the classic SPA symptom.
  2. Inspect a live URL. URL Inspection → "Test live URL" → "View tested page" → HTML. If the main content is missing from the raw HTML, it is client-rendered.
  3. Check the crawl of record. In URL Inspection, view the crawled HTML Google stored. If it is an empty shell, that is what is being judged.
  4. Read field Core Web Vitals. Search Console → Core Web Vitals, and PageSpeed Insights "Discover what your real users are experiencing". Ignore the lab numbers.
  5. Test a link preview. Paste a URL into LinkedIn or Slack and look at the unfurl. No title, no image, no description means the metadata requires JavaScript.
  6. Time to first byte by route type. Marketing pages should be well under 200ms from a CDN; authenticated pages can reasonably be slower.
  7. Check INP. A page that feels slow to click is usually running heavy hydration; profile the main thread on a mid-range device.

Fix in this order: render the content server-side, then get metadata right, then optimise bundles, then chase the final few Lighthouse points.

Frequently Asked Questions

Does Google still struggle with JavaScript? It does not fail outright, but client-rendered content goes through a rendering queue that can delay indexing by days or weeks. Server-rendered HTML is indexed on the first pass.

Do I need SSR for a logged-in dashboard? No. Crawlers do not need it, users are authenticated, and client-side rendering is perfectly appropriate once the app shell has loaded.

Is SSR expensive to run? Only when it is uncached. Static generation for content, SWR-style caching for semi-dynamic pages, and SSR only where personalisation genuinely requires it will keep hosting costs modest.

Can I keep my existing SPA and just add prerendering? You can prerender specific routes or serve crawlers a rendered variant, but the cleaner long-term fix is proper hybrid rendering. Prerender proxies add their own failure modes and are best treated as a stopgap.

Does SSR improve rankings by itself? No. It removes a technical barrier to being indexed and often improves Core Web Vitals, but content quality, internal linking and authority still decide where you rank.

Should we migrate slowly or all at once? Route by route. Start with the content most dependent on organic search, measure indexation and traffic for a month, then continue. A staged migration is reversible; a full rewrite rarely is.

Related reading: Core Web Vitals covers the metrics that judge the result; website performance optimisation is the action list; and the minimalist UI guide covers what to cut so there is less to render. Optimize your web architecture for top-tier Google rankings and lightning-fast speed with KEHEM IT.

Ranking poorly and blaming the content? Send us the URL — sometimes the rendering strategy is the problem.

Have a project in mind?

KEHEM designs and builds thoughtful websites, SaaS products, and business systems.

Talk to KEHEMExplore Services