Skip to content
GetCited Blog
Chapter 4 · Deepen your Knowledge

SEO for Site Migrations: A URL Migration Checklist That Keeps Your Rankings

How to inventory every URL, build a one-to-one redirect map in a spreadsheet, implement it in nginx, Apache or Next.js, and monitor Search Console until Google has moved everything across.

Updated October 202614 min read
In one line

A site migration keeps its rankings when every old URL that had traffic or links returns a single 301 to its closest new equivalent, the new site's canonicals, internal links, sitemaps and structured data all point at the new URLs, and the redirects stay in place for at least a year.

Most migration traffic losses come from the same short list: URLs nobody mapped, redirects that all go to the homepage, chains of three or four hops, a staging noindex that went live, and a new site that still links to old URLs. Every one of them is preventable with a spreadsheet and a test run before launch.

This guide is the checklist in order: what to collect before you touch anything, how to build the redirect map, working redirect code for the common servers, what to do on launch day, and what to watch in Search Console for the following months.

Illustration of a website being moved to a new address with its content intact

Types of migration and what each one risks

MigrationExampleURLs change?Main risk
Domain moveoldbrand.com → newbrand.comHost onlyLosing link equity if any path is not redirected
URL structure/blog/2023/05/post → /guides/postPathsUnmapped URLs, pattern rules that miss edge cases
Platform or CMSWordPress → Shopify or Next.jsOften, silentlyNew platform forces its own URL patterns, drops content or metadata
HTTPShttp:// → https://ProtocolMixed content, canonicals still on HTTP, redirect loops
Merge or consolidationTwo sites or subdomains into oneHost and pathsMany-to-one mapping, duplicate topics competing

Combine as few as you can. A domain move plus a new URL structure plus a new CMS on the same day makes any drop impossible to diagnose. If you must, at least keep paths identical across the domain change so the redirect is a single pattern rule.

Pre-migration checklist

The goal is a complete list of old URLs that matter, with enough data on each one to prioritise. No single source has them all, so combine:

A full crawl of the current site with Screaming Frog, Sitebulb or similar. Export every HTML URL with status, title, canonical and inlinks.
Search Console Performance, 16 months, by page. The interface exports 1,000 rows; use the API or a connector for more.
GA4 landing pages for the last 12 months, all channels, so you also protect referral, email and direct traffic.
Backlinks: Search Console's Links report (Top linked pages) plus a third-party backlink tool. Pages with external links but no traffic are easy to miss and still carry value.
XML sitemaps and, if you have them, server logs, which show URLs Googlebot still requests that no crawl would find.
Existing redirects from the current server config, CMS redirect plugin or CDN. Old redirects must be re-pointed to the new final URLs, not dropped.

Benchmark before launch so you can measure the result: organic clicks and impressions per page and per section, indexed page count from the Page indexing report, ranking positions for your top 100 to 200 queries, and Core Web Vitals per template. Save the crawl as well; you will diff against it later.

Prepare the new site: keep the staging site blocked with HTTP authentication rather than robots.txt or noindex, so nothing leaks into the index and nothing blocking gets copied to production. Carry over titles, meta descriptions, headings, body copy, image alt text and structured data for every page you are keeping.

URL mapping, step by step

The redirect map is the core deliverable. Build it as a spreadsheet with one row per old URL:

ColumnWhat goes in it
old_urlFull old URL, normalised (lowercase host, consistent trailing slash)
sourcesWhere it was found: crawl, GSC, GA4, backlinks, sitemap, logs
clicks_12m / ref_domainsOrganic clicks and linking domains, for priority
new_urlThe single destination, as a final 200 URL
match_typeexact slug, rewritten, consolidated, parent category, retired (410)
status_tested / hopsResult of the test run: final status and number of redirects
owner / notesWho signed off; reasons for non-obvious matches

Rule 1: one-to-one wherever a matching page exists. Each old URL redirects to the new page that serves the same intent. A product goes to the same product, an article to the same article.

Rule 2: no equivalent means closest relevant parent, or 410. A discontinued product can go to its category if the category meets the same need. If nothing on the new site is relevant, return 404 or 410. Google treats mass redirects to the homepage as soft 404s, so they do not pass value anyway.

Rule 3: every redirect points at a final URL. No chains. If /a already redirected to /b, and /b now moves to /c, update /a to go straight to /c. Googlebot follows a limited number of hops, and every extra hop slows crawling.

How to match old to new quickly. Export the new site's URLs (from the staging crawl or the CMS) to a second tab. Then match in passes:

1. Exact slug match: extract the last path segment from both lists
   =REGEXEXTRACT(A2, "([^/]+)/?$")
   =XLOOKUP(C2, New!C:C, New!A:A, "")

2. Title match for rows still empty: XLOOKUP the old page title
   against new page titles.

3. Pattern rules for whole sections, e.g.
   /blog/YYYY/MM/slug  →  /guides/slug

4. Manual review: sort the remaining rows by clicks_12m and
   ref_domains, and map the top few hundred by hand.

Have someone who knows the content sign off on the top pages; automated matches on slugs like /pricing or /about are usually right, but similar product names are often wrong. Pattern rules keep the server config short; the spreadsheet still needs one row per URL so you can test each one.

Normalise variants. Decide one canonical form for the new site (HTTPS, www or not, trailing slash or not, lowercase), and redirect every variant of the old URL in one hop: http://oldsite.com/Page should reach the new final URL directly, not via three normalisation steps.

Redirect code: nginx, Apache, Next.js and Vercel

Use permanent redirects: 301 or 308. Both pass signals the same way for Google; 308 also preserves the request method, which matters only for form posts and APIs.

nginx, using a map for a long list of one-to-one redirects plus a domain rule. The map block goes in the http context; large maps may need a higher map_hash_bucket_size.

map $uri $new_uri {
    default "";
    /blog/2023/05/site-speed-tips   /guides/site-speed;
    /products/blue-widget-v1        /products/blue-widget;
    /old-pricing                    /pricing;
}

server {
    listen 443 ssl;
    server_name www.example.com;

    if ($new_uri) {
        return 301 $new_uri;
    }

    # pattern rule for a whole section
    location ~ ^/blog/\d{4}/\d{2}/(.+)$ {
        return 301 /guides/$1;
    }
}

# domain move: every path to the same path on the new host
server {
    listen 443 ssl;
    server_name oldbrand.com www.oldbrand.com;
    return 301 https://www.newbrand.com$request_uri;
}

Apache .htaccess with mod_rewrite. Pick either RewriteRule or Redirect for a site and stick to it; mixing mod_rewrite and mod_alias rules leads to confusing order-of-execution bugs.

RewriteEngine On

# HTTP to HTTPS and non-www to www in one hop
RewriteCond %{HTTPS} off [OR]
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteRule ^(.*)$ https://www.example.com/$1 [R=301,L]

# one-to-one redirects
RewriteRule ^old-pricing/?$ /pricing [R=301,L]
RewriteRule ^products/blue-widget-v1/?$ /products/blue-widget [R=301,L]

# pattern rule for a whole section
RewriteRule ^blog/[0-9]{4}/[0-9]{2}/(.+)$ /guides/$1 [R=301,L]

Put the specific rules above broad patterns if they overlap, since [L] stops at the first match. For thousands of one-to-one rows, a RewriteMap in the main server config is faster than a long .htaccess.

Next.js (next.config.js). permanent: true sends a 308.

module.exports = {
  async redirects() {
    return [
      { source: '/old-pricing', destination: '/pricing', permanent: true },
      { source: '/blog/:year(\\d{4})/:month(\\d{2})/:slug',
        destination: '/guides/:slug', permanent: true },
    ];
  },
};

Vercel (vercel.json), for any framework deployed there:

{
  "redirects": [
    { "source": "/old-pricing", "destination": "/pricing", "permanent": true },
    { "source": "/blog/:year/:month/:slug", "destination": "/guides/:slug", "permanent": true }
  ]
}

Vercel caps how many redirects a deployment can define in config; check the current limit in its docs before pasting thousands of rows. For very large maps, load the spreadsheet as a JSON lookup in middleware and return a 301 or 308 from there.

Testing the redirect map before launch

Deploy the redirects to staging and test every row, not a sample. In Screaming Frog, use list mode with the old URLs and enable "Always follow redirects" to report the final URL and the number of hops. Or from a terminal:

while read -r url; do
  printf '%s\t' "$url"
  curl -s -o /dev/null -L --max-redirs 10 \
    -w '%{http_code}\t%{num_redirects}\t%{url_effective}\n' "$url"
done < old-urls.txt > redirect-test.tsv

Paste the output back into the sheet and flag any row where the final status is not 200, hops is more than 1, or the final URL does not equal new_url. Fix and retest until the flagged list is empty.

Launch-day checklist

Remove blocks: staging authentication off, no noindex in meta tags or X-Robots-Tag headers, production robots.txt in place and not blocking the old URLs (Google must crawl them to see the redirects).
Redirects live: rerun the test script against production on the top 500 URLs within the first hour.
Canonicals: every page's rel="canonical" points at its own new URL, not the old one and not staging.
Internal links: navigation, body links, breadcrumbs and footers link to new URLs directly. Linking through redirects works but wastes crawl and sends a mixed message about which URL is canonical.
Structured data: url, @id, item in breadcrumbs, logo and sameAs values point at the new URLs. Schema that still references old, redirecting URLs tells Google two different things about where the page lives.
hreflang annotations use new URLs on every language version.
Sitemaps: new XML sitemap with only new, 200, indexable URLs, referenced in robots.txt and submitted in Search Console.
Verification and analytics: Search Console verified for the new property, GA4 and tag manager firing on the new templates.

The Change of Address tool (domain moves only)

If you moved to a new domain or subdomain, use Search Console's Change of Address tool: open the old property, go to Settings → Change of address, and choose the new property. Both properties must be verified by you, and the old homepage and a sample of pages must 301 to the new site, or the validation step fails.

Do not use it for HTTP to HTTPS moves, www to non-www changes, or path changes on the same domain; those are handled by redirects alone. Bing Webmaster Tools has an equivalent Site Move feature for domain changes.

Post-launch monitoring

Days 1 to 7: check the Search Console Page indexing report for the new property daily. Watch for "Not found (404)" spikes, "Blocked by robots.txt", "Excluded by 'noindex' tag" and "Redirect error". On the old property, "Page with redirect" should grow as Google recrawls; that is expected. Use URL Inspection on your top 20 pages to confirm Google picked the new URL as canonical.
Weeks 2 to 8: compare clicks per section against the benchmark. Crawl the live site weekly for internal links to redirected URLs and for any chains. Check the Sitemaps report: submitted versus indexed counts for the new sitemap should converge. Review server logs or the Crawl stats report for Googlebot hitting 404s on old URLs you missed, and add those to the map.
Months 2 to 12: keep monitoring 404s, because old backlinks and bookmarks keep surfacing URLs.

Google's site move guidance says to keep redirects in place for as long as possible, and at least a year. In practice, keep them indefinitely: external links and old citations do not update themselves, and a redirect rule costs nothing to keep. Never let the old domain registration lapse after a domain move.

Some fluctuation is normal while Google recrawls. Google says a medium-sized site can take a few weeks for most pages to move, and larger sites longer. A drop that is still growing after a month, or is concentrated in one section, points to a mapping problem rather than normal reprocessing.

Why traffic drops after a migration

SymptomLikely causeFix
Whole site drops within daysnoindex or robots.txt block copied from stagingRemove it, request indexing on key pages, resubmit sitemap
404 spike in Page indexingUnmapped URLs (often from backlinks or logs)Add rows to the map; redirect to the closest equivalent
Old URLs still ranking weeks laterRedirects are 302, chained, or old URLs blocked in robots.txtMake them single-hop 301s and allow crawling
Google picks the old URL as canonicalCanonicals, internal links, sitemaps or schema still reference old URLsPoint every signal at the new URL
One section collapsesPattern rule wrong for that folder, or content trimmed on the new templateTest that section's rows; restore missing content
Long-tail traffic falls, head terms fineRetired pages redirected to the homepage or categoriesRebuild the useful pages or map them one-to-one
Rankings hold but conversions fallSlower templates, broken trackingCompare Core Web Vitals and GA4 events per template

Migrations and AI citations

ChatGPT, Perplexity and Google's AI Overviews cite specific URLs, and those citations can lag behind your migration. Clean single-hop redirects keep old cited links working, and consistent canonicals plus updated structured data help engines settle on the new URL. After launch, run your key pages through the AEO scanner to confirm AI crawlers can fetch the new templates, and check whether AI answers now cite the new URLs or keep citing the old ones with the AI visibility tracker.

Mistakes to avoid

Mapping only what the crawler found. Orphan pages with backlinks and URLs in the logs are missed by crawls. Combine all sources.
Redirecting everything to the homepage. Google treats it as a soft 404, and users land somewhere irrelevant.
Leaving old redirects pointing at old destinations. That creates chains. Update every existing redirect to the new final URL.
Blocking old URLs in robots.txt. Google cannot see a redirect on a URL it is not allowed to crawl.
Removing redirects after a few months. Links and citations keep arriving for years.
Changing everything at once. Domain, URLs, design and content in one release leave you nothing to roll back to. See SEO for web redesigns for the content side, and XML sitemaps for sitemap setup.

Questions people ask

How do I migrate URLs without losing SEO?
List every old URL from a crawl, Search Console, GA4, backlink data and sitemaps, then map each one to its closest new equivalent in a spreadsheet. Implement single-hop 301 or 308 redirects, test every row before launch, and make sure canonicals, internal links, sitemaps and structured data use only the new URLs. Keep the redirects for at least a year, ideally permanently.
Should I use 301 or 302 redirects for a site migration?
Use permanent redirects, 301 or 308, for every URL that has moved for good. Temporary 302 or 307 redirects tell Google the old URL may come back, so it can keep the old URL indexed longer. 301 and 308 pass signals the same way; 308 also keeps the request method.
How long does it take Google to process a site migration?
Google says a medium-sized site can take a few weeks for most pages to move, and larger sites take longer. Rankings often fluctuate during that period. A drop that keeps growing after a month usually means unmapped URLs, chains or conflicting canonical signals.
When should I use the Change of Address tool?
Only when moving to a new domain or subdomain, after 301 redirects are live and both properties are verified in Search Console. It is not used for HTTP to HTTPS moves or URL path changes on the same domain; redirects alone handle those.
How long should I keep redirects after a migration?
Google recommends keeping them as long as possible, generally at least one year. Keeping them permanently is safer, because backlinks, bookmarks and AI citations keep pointing at old URLs for years.

Related from GetCited

Technical SEO & AEO Audit

Run 417+ checks on schema, crawlability, and AI-readiness in one scan.

Explore Technical SEO & AEO Audit

Fix Dispatch

Deploy audit fixes directly to WordPress, Webflow, or Framer with one click.

Explore Fix Dispatch

AI Visibility Tracker

Monitor how AI engines cite your brand across ChatGPT, Perplexity, Gemini, and more.

Explore AI Visibility Tracker
Next step

AI visibility is half the journey. Let us show you the other half.