I recently rebuilt this website, moving it from WordPress to a custom Next.js site. The design changed completely, the URL structure changed in places, and the underlying technology changed entirely. The one thing I didn’t want to change was how Google sees it. Every page that had been indexed, and every link pointing to it, needed somewhere sensible to land.
The short answer to “how do you migrate from WordPress to Next.js without losing SEO?” is this: inventory every URL Google knows about, keep the ones you can, permanently redirect the rest, and rebuild the technical signals (titles, canonicals, sitemap, structured data) before you switch the domain over. Here’s exactly how I did it, with the real details from this site.
Why migrations lose rankings
Search rankings are attached to URLs. When a page moves and the old address returns a 404, Google eventually drops it, and any links other sites had pointed at it stop counting for anything. A redesign can quietly throw away years of accumulated trust in a weekend.
The other common losses are subtler: titles and meta descriptions that the SEO plugin used to generate and nobody recreated, a missing sitemap, noindex left on from staging, or content that used to be text now baked into images. None of these break the site visibly. They just make it harder to find.
Step 1: Inventory every URL Google already has
Start with what search engines actually know, not what you think the site contains. On this site, WordPress used Rank Math, which generated separate sitemaps for posts, pages, portfolio items, categories and project types. I pulled every URL from those live sitemaps before touching anything.
Then cross-check with Google Search Console. The Pages report shows indexed URLs, and the Performance report shows which ones actually earn clicks. Old WordPress sites tend to have more indexed URLs than their owners expect: tag archives, category pages, author pages, feeds, attachment pages.
Step 2: Keep URLs where you can
The safest redirect is the one you don’t need. My portfolio pages lived at /portfolio/<project> on WordPress, and they live at exactly the same addresses on the new site. No redirect, no signal lost, nothing to go wrong.
I changed URLs only where there was a real structural reason. Blog posts on WordPress sat at the root of the domain, like /why-most-small-businesses-dont-need-ai-yet. On the new site, every post lives under /blog/, which keeps the structure clear as the blog grows. That change was worth making, but only because every old address was redirected.
Step 3: Map every old URL to its closest new home
Each old URL should point to the page that best replaces it, not dump everything on the home page. Google treats mass redirects to the home page much like 404s. Here’s the map I used for this site:
- Each old post,
/<post-slug>, goes to/blog/<post-slug>. /workgoes to/portfolio, and/work/<project>to/portfolio/<project>./aboutand/about-mego to/journey, the new about page./contact-megoes to/contact, and/hometo/.- Category, tag and feed archives go to
/blog. Project type archives go to/portfolio. Author pages go to/journey. - Old sitemap addresses, like
/sitemap_index.xmland the per-type Rank Math sitemaps, go to the new/sitemap.xml.
Step 4: Use permanent redirects, at the server
Redirects need to be permanent (301 or 308) so search engines transfer the old page’s signals to the new one. A temporary redirect (302 or 307) tells Google the old URL is coming back, which is the opposite of what you want.
In Next.js, redirects live in next.config.ts, and setting permanent: true returns a 308. A 308 is the modern equivalent of a 301: both are permanent, and a 308 also preserves the request method. Because the rules run before any page renders, they’re fast and they work for crawlers. A simplified version of what this site uses:
async redirects() {
return [
{ source: '/why-most-small-businesses-dont-need-ai-yet',
destination: '/blog/why-most-small-businesses-dont-need-ai-yet',
permanent: true },
{ source: '/work/:slug', destination: '/portfolio/:slug', permanent: true },
{ source: '/category/:slug*', destination: '/blog', permanent: true },
];
}
Avoid redirect chains, where A points to B which points to C. Point every old URL straight at its final destination.
Step 5: Rebuild the signals your plugin used to handle
An SEO plugin on WordPress quietly does a lot of work. On a custom site, you have to do it on purpose. I used the same checklist I apply to any site, which I’ve written up as a technical SEO checklist for small businesses. For this rebuild, the important pieces were:
Titles, descriptions and canonicals on every page
Every page gets a unique title, a description, a canonical URL pointing to itself, and matching Open Graph and Twitter tags for link previews. On this site, one small helper generates all of these from the same inputs, so no page can ship without them.
A sitemap generated from real data
The sitemap is built from the same data files that build the pages. When I add a project or a post, it appears in the sitemap automatically with its date. There’s no separate list to forget to update.
Structured data
Every page includes a JSON-LD graph describing me as a Person and the site as a WebSite, linked by stable identifiers. Individual pages add their own types, like BlogPosting for articles and BreadcrumbList for navigation. This helps search engines connect the site, my profiles elsewhere and my work into one clear entity.
robots.txt and llms.txt
The robots file allows every crawler, including AI assistants, and points to the sitemap. The goal of a personal site is to be found and cited. I also publish an llms.txt file, a plain-text map of the site for AI tools, generated from the same data as the pages so it can’t drift out of date.
Step 6: Test before and after launch
Before switching the domain over, run the redirect list against the new build: every old URL should return a single 308 to the right place, and every new URL should return 200. After launch, the checks continue:
- Submit the new sitemap in Search Console.
- Use the URL Inspection tool on a few key pages to confirm Google can fetch and render them.
- Watch the Pages report for new 404s or unexpected exclusions over the following weeks.
- Run key pages through PageSpeed Insights to confirm the new build performs well for real users. If you’re new to those numbers, start with Core Web Vitals, explained for business owners.
Some fluctuation in the first weeks after any migration is normal while Google recrawls. What you want to avoid is a steady decline caused by something you could have caught.
Is it worth moving at all?
Not always. A well-maintained WordPress site can serve a business for years, and I explain when I’d keep one in how I choose between Next.js, WordPress, Webflow and Framer. I moved this site because I wanted full control over design, performance and structured data, and because a custom build let me turn the site itself into a working example of what I make.
If you’re planning a migration, or you’ve already done one and traffic dipped, get in touch. I’ll help you build the redirect map, rebuild what the old platform was doing behind the scenes, and launch without leaving your hard-earned rankings behind. You can also see the kinds of sites I build in my portfolio.




