Replatforming WordPress to Headless Next.js: An Incremental Migration Without Losing SEO Authority
A mid-size European company that has spent ten years building domain authority on WordPress does not take replatforming lightly. The SEO numbers are real. The organic traffic converts. And somewhere in the last decade, the editorial team accumulated a thousand posts, dozens of custom post types, and a plugin stack that would make a WordPress developer wince.
The argument for WordPress to Next.js migration is compelling: dramatically faster pages, proper React component architecture, reliable TypeScript types, no PHP plugin conflicts, and the ability to deploy to a CDN edge network rather than a single server in Frankfurt. But the failure mode is equally well-known. A team spends nine months rebuilding from scratch, launches the new site, and watches their rankings collapse because the crawl budget gets confused, half the canonical URLs silently changed, or the new sitemap was missing three hundred posts.
There is a better path. This post describes the incremental replatforming approach — running Next.js in front of your WordPress site via a reverse proxy, migrating routes page-by-page, and only cutting over the legacy site once every URL, redirect, and piece of structured data is verified in production.
Why Naive Rebuilds Destroy Rankings
Before getting into the mechanics, it is worth understanding what actually causes SEO damage during a migration.
The most common killer is URL change without a redirect. An e-commerce company rebuilds their product pages and changes /shop/product-name to /products/product-name. Every external link, every bookmark, every Google index entry now 404s or silently resolves to a different URL without a 301. Domain authority accumulated over years evaporates because the link graph pointing at the old URLs no longer leads anywhere meaningful.
The second killer is crawl confusion during transition. Google does not re-crawl your entire site the day you launch. It has a crawl budget, and it prioritises URLs it has seen before. If your new site changes the sitemap structure, removes the XML sitemap temporarily, or returns inconsistent canonical tags during a phased rollout, the crawler may spend weeks indexing the wrong version of your content.
The third is Core Web Vitals regression. Many teams migrate to Next.js expecting performance gains and do not get them because they inline too many client-side JS bundles, skip image optimisation, or let a third-party tag fire on every page load. Google now uses Core Web Vitals as a ranking signal. A migration that makes CWV worse can depress rankings even if everything else goes correctly.
All three of these failure modes are avoidable with the incremental reverse-proxy approach.
The Reverse Proxy Architecture
The core idea is straightforward: put Next.js in front of WordPress rather than replacing it all at once. Your domain points to a Next.js application. That application handles the routes you have already migrated natively. For every route that has not yet been migrated, it proxies the request transparently to the WordPress backend.
From Google's perspective, there is a single website. The URL structure is unchanged. The crawler keeps seeing valid responses at every URL it has indexed. From the user's perspective, migrated pages load significantly faster because they are served from Next.js with full App Router optimisation. Pages not yet migrated load from WordPress with an extra millisency or two for the proxy hop — negligible in practice.
In Next.js App Router, this proxy layer lives in middleware.ts:
// middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
const MIGRATED_ROUTES = new Set([
'/',
'/about',
'/services',
'/blog',
])
const MIGRATED_PREFIXES = [
'/blog/',
'/services/',
]
const WP_ORIGIN = process.env.WP_ORIGIN // e.g. https://wp-backend.internal
export function middleware(request: NextRequest) {
const { pathname } = request.nextUrl
const isMigrated =
MIGRATED_ROUTES.has(pathname) ||
MIGRATED_PREFIXES.some(prefix => pathname.startsWith(prefix))
if (isMigrated) {
return NextResponse.next()
}
// Proxy unmigrated routes to WordPress
const target = new URL(pathname + request.nextUrl.search, WP_ORIGIN)
return NextResponse.rewrite(target)
}
export const config = {
matcher: ['/((?!_next/static|_next/image|favicon.ico).*)'],
}
This code does not need to be clever. The migrated set grows over time as routes are moved to Next.js. The WordPress backend becomes purely an internal service — it no longer handles public traffic, and it does not need to be exposed to the internet at all once the migration is complete.
Preserving 301 Redirect Fidelity
If your WordPress site has accumulated redirects over the years — whether from the Redirection plugin, Yoast, .htaccess, or a combination — these need to be ported to Next.js before you cut each route.
Do not guess at what redirects exist. Export them. The Redirection plugin has a JSON export. Your server's .htaccess can be parsed. Once you have the full list, load them into a redirects array in next.config.ts:
// next.config.ts
const redirects = require('./redirects.json')
module.exports = {
async redirects() {
return redirects.map(({ source, destination, permanent }) => ({
source,
destination,
permanent: permanent ?? true,
}))
},
}
For sites with hundreds of redirects, this approach keeps the list auditable, version-controlled, and reviewable by the SEO team without requiring a developer for every change. Verifying redirect fidelity before each route migration is non-negotiable — a missed 301 is silent in the application logs but immediately visible in Search Console.
Porting Custom Post Types and ACF Fields
WordPress's custom post types and Advanced Custom Fields are the part of the migration that teams consistently underestimate. Many WordPress sites have a decade of editorial infrastructure built on CPTs: case studies, team members, product specs, event listings, testimonials. Each one has a set of ACF fields, a template, and possibly a custom query that drives a listing page.
The first question to answer is whether you want a headless CMS (such as Contentful, Sanity, or Payload CMS) as the new content layer, or whether you will serve content directly from Next.js files or a custom database. This is not a technical decision alone — it involves the editorial team, who may or may not want to keep editing in WordPress.
The path of least resistance is keeping WordPress as the headless CMS and exposing CPTs through the WordPress REST API or WPGraphQL. Your Next.js pages fetch from the WordPress API at build time (for static content) or at request time (for personalised or frequently updated content). WordPress remains the editorial interface; Next.js becomes the rendering layer.
// lib/wp-api.ts — fetch a custom post type via WPGraphQL
export async function getCaseStudies(): Promise<CaseStudy[]> {
const res = await fetch(process.env.WP_GRAPHQL_ENDPOINT!, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
query: `
query GetCaseStudies {
caseStudies(first: 100) {
nodes {
id
title
slug
acfCaseStudy {
client
industry
outcome
techStack
}
featuredImage {
node { sourceUrl altText }
}
}
}
}
`,
}),
next: { revalidate: 3600 },
})
const { data } = await res.json()
return data.caseStudies.nodes
}
If you decide to migrate content out of WordPress entirely, do it by CPT rather than all at once. Export the posts, import them into the new store, verify the canonical URLs are unchanged, then cut the CPT in the proxy config.
Core Web Vitals That Actually Move Rankings
The entire point of leaving WordPress for Next.js is faster pages. But faster pages only improve rankings if you optimise the metrics Google actually measures: Largest Contentful Paint (LCP), Interaction to Next Paint (INP), and Cumulative Layout Shift (CLS).
LCP is almost always the hero image on the page. Use next/image with the priority prop for the largest above-the-fold image on every template. Do not leave this as an afterthought — a single template type (blog post, product page, case study) with an unoptimised LCP image will drag your entire category's average down.
import Image from 'next/image'
// In your blog post template
<Image
src={post.featuredImage.url}
alt={post.featuredImage.alt}
width={1200}
height={630}
priority // LCP image — load immediately
sizes="(max-width: 768px) 100vw, 1200px"
/>
CLS is typically caused by images without explicit dimensions, late-loading web fonts, or dynamically injected banners and cookie notices that shift content after paint. In Next.js, explicit width and height on every next/image eliminates the most common CLS source. For fonts, use next/font with display: swap and preload enabled.
INP replaces First Input Delay as of 2024 and measures responsiveness to all interactions, not just the first. Excessive client-side JavaScript is the primary cause of poor INP. Audit your bundle with @next/bundle-analyzer and ruthlessly defer or remove JavaScript that is not needed for the initial render. Third-party scripts — analytics, chat widgets, A/B testing SDKs — are often the worst offenders and should load with strategy="lazyOnload" via next/script.
The Cut-Over Sequence
Timing the final cut-over — when the WordPress backend stops handling any public traffic — requires coordination between your developer, your SEO team, and your hosting setup.
The sequence that minimises risk:
- Migrate all routes through the reverse proxy and verify each one in Search Console. Do not cut over until every URL that has indexing data in GSC returns a 200 from the Next.js application.
- Verify the sitemap generated by Next.js matches the WordPress sitemap, URL for URL. Use a diff tool. Missing URLs before cut-over are fixable; missing URLs discovered after cut-over have already sent signals to Google.
- Audit canonical tags on every template. The canonical should always point at the production domain with the correct slug. A misconfigured canonical that points at the WordPress backend URL (which will soon be internal-only) is a hard-to-diagnose problem.
- Freeze the WordPress backend before going dark. Stop new content from being published in WordPress while you migrate the last batch of routes. A content freeze of 24–48 hours is acceptable; weeks of drift between the WordPress draft and the Next.js build is not.
- Deploy, watch Search Console, and monitor CWV in real-user monitoring for the first 30 days. Crawl rate changes, impressions dips, and CWV regressions are all visible in GSC within days of launch.
Do not switch DNS and then immediately take the WordPress backend offline. Keep it running internally for at least 30 days as a fallback. The proxy config can restore a route to WordPress in seconds if something unexpected surfaces in production.
What the Migration Does Not Fix
Replatforming to Next.js solves performance, architecture, and developer experience. It does not fix thin content, duplicate content, or a backlink profile that has been neglected for years. Teams sometimes conflate "our WordPress site is slow and creaky" with "our SEO strategy is underperforming" and expect the migration to fix both. It will fix the technical signals. The content and authority signals require separate work.
If your site has significant duplicate content issues — canonical confusion from WordPress categories, tags, and archive pages creating multiple paths to the same content — the migration is an opportunity to clean that up. The Next.js sitemap should include only canonical URLs. But the clean-up itself is editorial work, not a side effect of the platform change.
When to Call in Outside Help
A WordPress to Next.js migration of a site with established SEO authority is not a weekend project. The reverse proxy architecture is straightforward to set up but requires sustained attention to detail across weeks of route-by-route migration. The costs of getting it wrong — a dropped canonical, a missed 301, a CWV regression — can outweigh the benefits of the new platform for months.
Wolf-Tech helps mid-size European businesses through exactly this kind of legacy code optimization and digital transformation work. We have run this playbook for companies with five years of SEO authority and for companies with fifteen, in markets where a ranking drop of ten positions is a material revenue event. If you are planning a replatforming project and want an outside review of your migration strategy before you start, or if you are mid-migration and something is not going as expected, contact us at hello@wolf-tech.io or visit wolf-tech.io to arrange a consultation.

