We recently moved our own website from WordPress to Next.js, and we've rebuilt client sites whose search rankings had to survive the move. The reasons are consistent: faster pages, fewer plugins to patch, better developer experience and more control over SEO. So is the risk: a migration is the moment years of search visibility can disappear.
Rankings rarely drop because of the framework. They drop because URLs change without redirects, content and metadata get lost, or technical signals regress. This checklist is how we avoid that.
Before you build
1. Inventory every URL
Combine every source you have: the XML sitemaps (with Yoast, sitemap_index.xml links to one sitemap per post type), a full crawl of the live site, Search Console's page reports, analytics landing pages and a backlink export. Don't forget custom post types, category and author archives, pagination, feeds and media URLs.
2. Classify each URL
For every URL decide: keep (same path), move (new path, 301), merge (consolidate thin or duplicate content into a stronger page, 301) or retire (genuinely obsolete — 301 to the closest relevant page, or 410 if nothing fits). Migrations are a great moment to prune weak content, but every retired URL still needs a destination.
3. Capture what each page ranks with
Export titles, meta descriptions, H1s, canonicals, structured data and internal links for your important pages. If a page ranks, its on-page signals are part of why — carry them over deliberately, then improve them.
Building the Next.js site
4. Decide on trailing slashes early
WordPress uses trailing slashes (/about/); Next.js redirects them away by default. Mismatches create an extra redirect hop on every old link. If you're keeping WordPress-style URLs, turn trailing slashes on:
import type { NextConfig } from "next";
const nextConfig: NextConfig = {
trailingSlash: true, // /about → /about/, matching WordPress
};
export default nextConfig;5. Build the redirect map in code
Keep redirects in version control, generated from data where possible — for example, imported posts that move from /<slug>/ to /blog/<slug>/. Every redirect should be permanent and single-hop: old URL → final URL, never through intermediate redirects.
const nextConfig: NextConfig = {
trailingSlash: true,
async redirects() {
return [
{ source: "/overview/", destination: "/about/", permanent: true },
{ source: "/expertise/:slug/", destination: "/services/:slug/", permanent: true },
// ...generated entries for every moved blog post
];
},
};6. Recreate metadata with the Metadata API
Every page needs a unique title, meta description and a self-referencing canonical. In the App Router, generateMetadata keeps this next to the content it describes:
export async function generateMetadata({ params }: PageProps<"/blog/[slug]">) {
const { slug } = await params;
const post = getPost(slug);
return {
title: post.title,
description: post.description,
alternates: { canonical: `https://example.com/blog/${slug}/` },
openGraph: { type: "article", publishedTime: post.date },
};
}7. Carry over structured data
If your WordPress SEO plugin output Organization, BreadcrumbList or Article schema, replicate it with JSON-LD in your pages — and add what was missing, such as Service for service pages or FAQPage where you show FAQs. Validate with Google's Rich Results Test.
8. Pre-render, and keep pages fast
Generate content pages statically (generateStaticParams) so crawlers receive complete HTML without waiting for JavaScript. Self-host fonts, size images properly and keep client-side JavaScript to what's truly interactive. Better Core Web Vitals are one of the main upsides of the move — don't give them back.
9. Generate sitemaps and robots.txt from your content
Use app/sitemap.ts and app/robots.ts so new pages appear automatically, with real lastModified dates rather than "now" on every build. Block indexing on preview deployments so staging never competes with production.
Launch and after
10. Test the migration before DNS changes
On a staging URL, run every old URL through the new site and confirm each returns a single 301 to the right destination, or a 200 for kept URLs. Crawl the new site for broken internal links, missing titles, duplicate descriptions and accidental noindex tags.
11. Launch, then tell Google
Switch DNS, verify the domain in Search Console, submit the new sitemap and request indexing for key pages. Keep the old sitemap available briefly so Google can discover the redirects.
12. Monitor for four weeks — and keep redirects forever
Watch Search Console's page indexing and crawl reports, your server's 404 log and rankings for your top pages. Fix gaps quickly. Redirects are permanent infrastructure: removing them later breaks every old backlink.
Common pitfalls
- Redirecting everything to the home page. Google treats mass redirects to an unrelated page as soft 404s. Map each URL to its closest equivalent.
- Redirect chains. Old URL → temporary URL → new URL wastes crawl budget and dilutes signals.
- Losing images. Media URLs (
/wp-content/uploads/...) often rank in image search and are linked from other sites. Import the files and redirect or preserve the important ones. - Dropping content "to be added later". Thin new pages rarely hold the rankings of the full pages they replaced.
- Forgetting internal links. Update links in your content to point at final URLs, not redirects.



