Client-only SPAs feel fast in a demo. They are quiet disasters for organic search. If your marketing site or marketplace is still a Create React App (or any CSR-only shell) that serves an empty HTML document and waits for JavaScript to paint the real content, crawlers and users who arrive from Google are not seeing what you think they see.
We wrote about this pattern in the Emprenur case study: a Latino freelance marketplace that launched with effectively zero indexable pages on its architecture — then rebuilt to production-grade technical SEO before the public growth phase. This Insight is the companion piece: why CRA/client-only SPAs fail crawlability, what Next.js SSR/SSG actually fixes, and a checklist founders can use before they spend another quarter “optimizing content” on a stack that never ships HTML.
What crawlers get from a classic CRA shell
A typical CRA production build returns a short HTML file: a root <div id="root"> , a JS bundle, and almost no meaningful text. The real titles, headings, product copy, job listings, and meta tags appear only after the browser downloads, parses, and executes JavaScript — then fetches APIs.
Modern Googlebot can run JavaScript, but “can” is not “will, reliably, completely, on your timeline, for every URL.” Rendering is queued, budgets are finite, and soft-404s, empty shells, and client-only routes still show up as thin or missing in Search Console. Other crawlers (and many social/link unfurlers) are worse. If your business depends on organic discovery — marketplaces, content hubs, local services, B2B SaaS marketing — CSR-only is a structural handicap, not a temporary inconvenience.
Symptoms founders notice too late
1. Almost no pages in the index (or only the homepage) despite “lots of routes” in the React router. 2. View-source shows nothing useful — no H1, no product text, placeholder titles. 3. Social shares look empty — OG tags injected only after JS. 4. Content teams write articles that never rank because the template never ships crawlable HTML. 5. Performance theatre — Lighthouse on a warmed client session looks fine while first-request HTML stays hollow.
None of these require inventing rankings. They are architectural tells. Emprenur’s launch architecture was the extreme case: zero indexable pages until the stack changed. Your site may be milder — and still leave money on the table every week CSR stays the default.
What Next.js SSR/SSG actually changes
Moving to Next.js (or another HTML-first framework) is not a rebrand of React. It changes the first response : SSR (Server-Side Rendering) — the server renders HTML for the request, including content and meta, then hydrates on the client. Crawlers get real text on first fetch. SSG / ISR — pages are pre-rendered (and can revalidate), so HTML exists at the edge/CDN without waiting on a cold Node render for every hit. File/app routing with metadata APIs — titles, descriptions, and Open Graph become first-class server concerns, not afterthoughts in useEffect .
You still need good information architecture, internal links, and content. But you stop asking Google to reconstruct your product from a blank shell. That is the Emprenur-shaped fix: migrate the frontend so every important URL serves complete, crawlable HTML on first request — no JavaScript execution required on the crawler’s side for the core content.
Migration checklist (founder-readable)
1. Inventory routes that must rank — homepage, category/job/profile templates, blog, pricing, landing pages. If it should appear in search, it needs HTML on first response. 2. View-source every critical URL today. If you cannot read the H1 and primary copy in the raw HTML, crawlers are guessing. 3. Choose SSR vs SSG/ISR per template — highly dynamic personalized shells may stay client; marketing and catalog pages should not. 4. Move meta to the server — unique title/description/OG per URL; stop injecting only after mount. 5. Ship a real sitemap and robots policy that matches the new HTML routes — not a SPA catch-all fantasy. 6. Preserve or 301 old URLs during the CRA→Next cutover so equity and bookmarks do not die. 7. Harden while you migrate — types, tests, and dead-code cleanup belong in the migration, not “phase two.” That is how you avoid a second rescue. 8. Verify in Search Console after launch — coverage, crawled HTML samples, and enrichment — without promising invented rank jumps.
What “done” looks like
Done is not “we use Next.js on the README.” Done is: critical URLs return meaningful HTML without executing your app bundle; metadata is correct in the first response; sitemaps list the real pages; redirects cover the cutover; and your team can explain which templates are SSR, SSG/ISR, or intentionally client-only.
If you want the narrative of how that played out on a live marketplace, read the Emprenur case study on CodeFlamme — rebuilding a Latino freelance marketplace for search visibility. If you are staring at a CSR shell and a quiet Search Console, the stack conversation belongs before another content sprint.

