HomeAboutServicesWorkBlogFAQContact

Migrating from React SPA to Next.js for SEO and AI Crawlers: What Actually Changes

Why a client-rendered React SPA is invisible to most AI crawlers like GPTBot and ClaudeBot, and what actually changes when you migrate to Next.js with static generation.

Migrating from React SPA to Next.js for SEO and AI Crawlers: What Actually Changes

Short answer: a client-rendered single-page app can still rank in Google, which executes JavaScript, but it's largely invisible to AI crawlers like GPTBot, ClaudeBot, and PerplexityBot, which read raw HTML. Migrating to Next.js with static generation puts the actual content into the HTML response itself, which is what both traditional SEO and AI visibility (AEO/GEO) now depend on.

I rebuilt this portfolio twice in the same week. The first version was a single-page React app, Vite, client-side rendered, fast to build. It looked good and worked fine for a human visitor. Then I sat down to add a blog and think properly about SEO, and realized the first version had a real problem: most AI crawlers don't execute JavaScript.

Do AI crawlers actually render JavaScript?

Googlebot renders JavaScript. It has for years, and it does it reasonably reliably. So if you've been optimizing for Google search rankings, a client-rendered single-page app can work, with caveats around rendering budget and timing that are still worth knowing about.

But Google isn't the only thing reading your site anymore. GPTBot, ClaudeBot, PerplexityBot, and the other AI crawlers that feed answers into ChatGPT, Claude, and Perplexity mostly fetch raw HTML. They don't run a headless browser, they don't wait for useEffect to fire, they don't see anything your JavaScript renders after the fact. Point one of them at a bare <div id="root"></div> and that's exactly what they see: nothing.

If you want your content to be findable, and increasingly, citable, by both traditional search and AI systems, the content needs to exist in the HTML that gets served on the first request. Not after hydration. Not after a fetch call resolves. In the initial response.

What does migrating to Next.js actually change?

Next.js's App Router, used with static generation (generateStaticParams, static rendering by default), pre-renders your pages to real HTML at build time. A crawler, human-driven browser, Googlebot, GPTBot, whatever, gets the same fully-formed document whether or not it runs JavaScript. That's the whole point, and it's the reason I moved this site over.

A few things surprised me in the process:

  • Route-level metadata is the easy part. Next.js's Metadata API lets every page export its own title, description, and Open Graph tags without any extra library. For a single-page app, you'd need something like react-helmet bolted on, and it still wouldn't help non-JS crawlers see the content, only the head tags injected by JS, which has the same fundamental problem.
  • Structured data gets a lot less fragile. On the old static HTML site, I had a comment above the FAQ JSON-LD block that said "keep this in sync by hand with the FAQ section." That's a bug waiting to happen: two sources of truth that drift apart the first time someone edits one and forgets the other. With server-rendered pages, the JSON-LD is generated from the exact same data array that renders the visible FAQ. There's no second copy to forget. This site's FAQ page and every blog post's Q&A section now work exactly this way.
  • You don't need a heavy client-side framework for content pages. Blog posts and case studies here are plain Markdown, parsed at build time, rendered as static HTML with zero client-side JavaScript for the content itself. The only Client Components on this site are the ones that actually need interactivity: the mobile nav menu, the contact form, the FAQ accordion. Everything else is a Server Component by default.

Does this replace having good content?

Moving to Next.js doesn't replace having something worth saying. Structured data and static HTML make your content legible to crawlers, they don't make thin content rank, and they definitely don't make a hollow FAQ page useful to an AI system deciding what to cite. The infrastructure is a prerequisite, not a strategy. This is the same principle behind the digital marketing and SEO work I do for client sites: fix the technical foundation first, then the content has somewhere real to land.

How do you check if your own site has this problem?

If you're evaluating whether to make this move for your own site, the honest test is: open your homepage's "view source" (not the rendered DOM in devtools, the actual raw response) and see how much of your real content is in there. If it's mostly empty divs and script tags, that's the gap.

Frequently asked questions

Not always bad for Google specifically, since Googlebot does render JavaScript, but it's effectively invisible to AI crawlers like GPTBot, ClaudeBot, and PerplexityBot, which mostly fetch raw HTML and don't execute JavaScript or wait for content to render after the page loads.