SEO for Single-Page Applications
Single-page apps render content with JavaScript, which creates a tension with search engines: crawlers index fastest and most reliably when meaningful HTML arrives in the initial response. A pure client-rendered SPA can ship a near-empty <div id="root"> to the crawler and lose ranking for content it can't see quickly.
The fix is to get real HTML to crawlers — through server-side rendering or static generation — and to give every route proper metadata. Modern meta-frameworks (Next.js, Nuxt, SvelteKit) make this the default rather than an afterthought.
TL;DR
- Use SSR or SSG for public, indexable pages (Next.js, Nuxt, SvelteKit).
- Give every page a unique title, description, and canonical URL.
- Add structured data (JSON-LD) for rich results.
- Ship a sitemap and robots.txt, and keep Core Web Vitals fast.
Quick Example
Per-page metadata and a canonical URL — the minimum every indexable route needs:
Core Concepts
Rendering strategies
Metadata & canonical URLs
Each page needs a unique <title> and <meta name="description">, Open Graph/Twitter tags for social, and a <link rel="canonical"> to prevent duplicate-content issues from query params and trailing slashes.
Structured data
JSON-LD describes your content to search engines and can earn rich results:
Best Practices
A public-page SEO checklist:
- ✅ SSR or SSG (not pure CSR) for indexable content
- ✅ Unique
title+meta descriptionper page - ✅ Canonical URL on every page
- ✅ XML sitemap and
robots.txt - ✅ Structured data where it applies
- ✅ Fast Core Web Vitals — see Web Performance
Common Mistakes
Pure client rendering for public content
Duplicate or missing metadata
FAQ
Why is SEO harder for SPAs?
Because content is rendered by JavaScript after the page loads. Crawlers can execute JS, but it's slower and less reliable than reading HTML directly — so a client-only SPA risks delayed or incomplete indexing. Server-rendering the HTML removes that risk.
SSR or SSG — which should I use?
SSG (static generation) for content that doesn't change per request — it's the fastest and most SEO-friendly. SSR for pages that are dynamic or personalized at request time. Many frameworks let you mix both per route, plus ISR for large sites.
Does Google actually run JavaScript?
Yes, Googlebot renders JS — but on a deferred, resource-limited pass, and other crawlers and social scrapers often don't. Relying on client rendering for critical content is a gamble; SSR/SSG makes indexing immediate and universal.
Do I need structured data?
It's not required to be indexed, but JSON-LD structured data helps search engines understand your content and can unlock rich results (stars, FAQs, breadcrumbs) that improve click-through. It's high-value for articles, products, and FAQs.
Related Topics
- Next.js — React SSR/SSG framework
- Nuxt — Vue SSR/SSG framework
- Web Performance — Core Web Vitals
- HTML Fundamentals — Semantic, crawlable markup
- Frontend Development — The broader landscape