A redirect map is a spreadsheet with one row for every URL your old site ever served, the exact new address it should point to, and the status code to use. That is the whole artifact, and it is the load-bearing file of any migration: every ranking that survives a platform move survives because a row in this file was correct. WPBuildAI builds the map before design starts, for three reasons: it is generated from a crawl rather than from memory, it converts preservation into something testable row by row, and it surfaces the pages nobody remembered while there is still time to decide what to do with them. Here is what goes in it, where the rows come from, and the mistakes that make a map look complete when it is not.
What does the file actually contain?
At minimum two columns, old URL and new URL. In practice five columns make it usable for the years it will live.
Old URL. The full path as it was served, including whether it carried a trailing slash, because those are different addresses to a server.
New URL. The exact destination, absolute, with the correct protocol and host. Not a pattern, not an approximation.
Status. Almost always 301, a permanent move. Google’s redirect guidance treats a permanent redirect as the strongest signal that an address has changed, and the HTTP definition of 301 says the same in protocol terms. A 302 says the move is temporary, which is not what you mean.
Source. Where you found this URL: crawl, Search Console, analytics, logs, sitemap, or existing redirect rules. This tells you how confident to be and what to recheck.
Decision note. For any row where the destination is not obvious, one line explaining the choice. Six months later this is the difference between a maintainable file and a mystery.
Sort by whatever earned the most traffic, so the rows that matter get the most attention.
Where do the rows come from?
Six sources, and the single biggest mistake is using only the first one that comes to mind, the sitemap. A sitemap lists what the site currently wants indexed, not what it has ever served.
| Source | What it uniquely catches | How to get it | Priority |
|---|---|---|---|
| Full crawl of the live site | Everything reachable by following links | Desktop crawler, one run | The backbone |
| Search Console pages export | URLs Google knows that your crawler never reached | Export over the longest period available | High |
| Analytics, two years of pages | Old landing pages and campaign URLs | Export all pages with any sessions | High |
| Server access logs | Addresses still receiving requests, including 404s | Ask your host | Highest, if available |
| XML sitemap, current and archived | Intended pages, as a cross check | Your sitemap URL | Supplement only |
| Existing redirect rules | Earlier moves, so you can flatten chains | SEO plugin, server config, host panel | Essential for chains |
Deduplicate the combined list, normalize case and trailing slashes, and you have your row count. It will be larger than you expect, which is the point of doing it this way. The method behind it is in what is a crawl-first migration.
How do you decide each destination?
By topic proximity, not by convenience. Find the situation below and apply its rule.
| Old page situation | Destination | Status | Why | Verdict |
|---|---|---|---|---|
| Direct equivalent exists | The equivalent page | 301 | Signals transfer to the obvious successor | The easy majority, do these first |
| Merged into a larger page | The merged page | 301 | The content is still there, in a bigger container | Fine, note the merge |
| No equivalent, topic still covered | Nearest relevant parent | 301 | Keeps the visitor in context and passes value | Far better than the homepage |
| Deliberately removed forever | Nothing, return gone | 410 | 410 tells crawlers to stop asking | Honest for retired content |
| Never should have existed | Nothing, return not found | 404 | Session URLs, spam pages, test pages | Do not map noise |
The rule that saves the most value: redirect to the closest surviving page by topic rather than to the top of the site. A visitor who clicks a five year old link and lands on the homepage has to start their search again, and search engines reading that pattern learn the old subject is no longer covered.
The rule that saves the most time: no blank cells. A blank is a decision nobody made, and blanks become 404s at launch. If a row is genuinely undecidable, write “410, retired” and move on with intent.
Why must every row resolve in a single hop?
Because chains cost crawl efficiency and clarity, and they accumulate across successive migrations until someone finds a five hop path.
Chains happen when an old URL redirects to an address that itself redirects. They work in a browser, which is why they survive. If your source data contains earlier redirect rules, resolve them: map the original address directly to the final destination.
Loops happen when A redirects to B and B redirects back to A, usually through a mismatch between a trailing slash rule and a canonical rule, or between an http to https rule and a www rule. They are invisible in a spreadsheet and immediately fatal in production, which is why the map has to be tested against the running site rather than reviewed by eye. The testing workflow is in how to test 301 redirects after a migration.
Protocol and host belong in the destination rather than in assumptions. If you are also moving from http to https, or adding or removing www, those rules combine with your content rules, and combining them badly is the most common source of loops.
Which URL categories does everyone forget?
The ones that are categories rather than pages, because a reviewer scans the map, sees the important pages present, and approves it.
Paginated archives, page 2 and onwards for blog listings, categories, and tags, carry crawl paths to deep content even when they get little direct traffic. Tag and category pages are often dozens or hundreds of addresses, some ranking for real queries. Attachment and media URLs matter twice over, since WordPress creates a page per uploaded file by default and the image files themselves have addresses image search may be sending traffic to, which is covered in how to migrate WordPress images and media without broken links.
Then feeds, which sometimes have subscribers. Author pages, date archives, and search result URLs, usually low value and occasionally a surprising number of indexed addresses. And parameter variants from filters, sort orders, and tracking, which should be decided once and applied as a rule.
Check for categories rather than for favorites, and the row count stops surprising you. The archive specific version is in how to move WordPress blog posts without losing rankings.
How do you test the map?
As data before launch, and as behavior afterwards. Both are mechanical, and neither is a review meeting.
Before launch, check the file: no blanks, no duplicate old URLs, every destination present in the new site’s URL list, and no destination that is itself an old URL in the same file.
After launch, request every old URL and record the status and the final destination. Every row should return a single 301 to the mapped address, and that address should return 200. Anything else, a 404, a chain, a loop, or a destination that differs from the map, is a defect with a name and a fix.
Automate it. On a thousand row map, a script does in two minutes what a person cannot do reliably at all. Rerun it a week later, because a deploy can silently change rules, and again a month later. Search Console provides the third check by reporting what Google actually encountered, which sometimes differs from what your own test found.
When is a redirect map not worth building?
On a site with no history worth preserving. A site launched three months ago with no backlinks, no indexed archive, and thirty visitors a month has nothing for the map to protect, and the honest advice is to skip it and launch.
It is also unnecessary when no URL is changing. A move that keeps every address, a host change or a rebuild on identical paths, needs backup discipline and testing rather than a map, because Google distinguishes moves with URL changes from moves without them for exactly this reason. Preserving addresses wherever possible is the cheaper strategy, argued in should you keep your old URLs after a migration.
Everywhere else, the map is the work. Keep it with the site in version control and update it whenever a URL changes, because redirect rules are permanent infrastructure rather than launch scaffolding, and the next migration should start from this file instead of from an archaeology project. The wider checklist it belongs to is in WordPress migration SEO checklist.
Key takeaways: building a redirect map that holds
The map is one row per old URL with an exact destination and a status code. Two columns are the minimum, five make it maintainable, and no cell is ever left blank.
Build it from a crawl plus Search Console, analytics, logs, and existing rules. Building it from the sitemap produces a map of what you meant to publish rather than what you actually served.
Redirect to the nearest surviving page by topic. Homepage redirects for unrelated content are close to worthless, and 410 is the honest answer for content that is genuinely retired.
Every row must resolve in one hop to a 200. Test the whole map mechanically after launch, again a week later, and keep the file with the site, because the rules are permanent infrastructure.
Quick answers
What is a redirect map? A spreadsheet with one row for every URL the old site served, the exact new address each should point to, and the status code to use. WPBuildAI builds it from a crawl before design starts, because it decides whether a migration preserves rankings or loses them, and it is the only artifact in a migration that can be tested row by row.
How do I build a redirect map for a website migration? Crawl the live site for every reachable URL, then add the historical sources a crawl cannot reach: Search Console, analytics, server logs, your XML sitemap, and any existing redirect rules. Deduplicate the combined list, then assign every old URL a destination. Anything with no obvious match gets a deliberate decision written into the row rather than a blank cell.
What should I do with old pages that have no equivalent? Send them to the most relevant remaining page, usually a parent category, rather than the homepage, because homepage redirects for unrelated content are commonly treated as soft errors and carry little value. If a page is genuinely gone and should stay gone, a 410 status is the honest answer and it tells search engines to stop asking.
How many rows should a redirect map have? More than your page count, usually two to five times more. A 200 page site commonly produces 600 to 1,000 rows once you include paginated archives, tag and category pages, attachment URLs, feeds, parameter variants, and addresses that exist only in old backlinks. That gap between pages and rows is exactly where migrations lose traffic.
Is a wildcard rule not simpler than mapping every URL? Simpler and riskier, and the risk is the kind you do not notice. Wildcards work well when a whole directory moves with its structure intact underneath it. They fail silently when the structure changes, sending twenty different pages to one destination or producing redirect loops nobody catches until traffic drops. Use patterns where the pattern is genuinely true of every URL it covers, and explicit rows everywhere else.