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
| Metric | Server-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:
| Mode | How it works | Best for | Trade-off |
|---|---|---|---|
| SSG (static generation) | HTML built at deploy time | Marketing pages, blogs, docs | Rebuild required for content changes |
| ISR / SWR (incremental) | Static HTML, regenerated in the background | Large content sites, catalogues | Slightly stale first view |
| SSR (per request) | HTML rendered on each request | Personalised pages, pricing by region | Server cost and latency |
| CSR / SPA | Shell + client-side data fetch | Authenticated app dashboards | Poor SEO, slower first paint |
| Streaming SSR | HTML sent progressively as it renders | Long pages with slow data sources | More 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.
hreflangtags 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.txtthat 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:
- Check indexed page counts. Search Console → Pages → "Indexed" versus the number of URLs in your sitemap. A large gap is the classic SPA symptom.
- 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.
- 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.
- Read field Core Web Vitals. Search Console → Core Web Vitals, and PageSpeed Insights "Discover what your real users are experiencing". Ignore the lab numbers.
- 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.
- Time to first byte by route type. Marketing pages should be well under 200ms from a CDN; authenticated pages can reasonably be slower.
- 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.