A migration fails in the inventory, not in the code. One path missing from the redirect map is one broken link that nobody notices for a month.
Start with three lists
- A crawl of the live site from the home page, breadth first.
- Every URL in the sitemap, including pages nothing links to.
- Every URL with impressions in Search Console for the last 90 days.
The union of those three lists is the inventory. Anything missing from all three is a page nobody uses, and it still deserves a line.
Give every path one of five dispositions
| Disposition | What happens |
|---|---|
| Keep | Same path, same content, rebuilt |
| Move | New path, with one permanent redirect |
| Merge | Two thin pages become one, both redirect to it |
| Retire | Removed, redirected to the closest relevant page |
| Hold | Not published in the new build, tracked until it is |
Nothing else is allowed. A path with two dispositions is a path two people will handle differently.
A worked inventory
Cedar and Slate Interiors, a fictional client, 118 paths.
source: live crawl 118 urls, sitemap 121 urls, search console 96 urls
union: 131 unique urls
dispositions
keep 84 including the 12 service pages and 20 portfolio items
move 27 old /project-<name> paths to /work/<name>
merge 9 three pairs of thin location pages, one page each
retire 8 campaign pages from 2023, redirect to /services
hold 3 two legal drafts and one supplier page, tracked by name
redirect rules
- one hop only: the old path points at the final page, not at another redirect
- trailing slash: the new site serves /services, so the map uses that form
- case: all lowercase, because the old host was case sensitive
checks after the build
- 131 fetch results recorded in a file beside the map
- 27 move paths resolve in one hop
- 9 merge paths land on a page that answers the original query
- 8 retire paths land on a relevant page, not the home page
The week, in order
- Day 1. Build the union list and count it. Agree the five dispositions.
- Day 2. Assign a disposition to every path, and name the target for each move.
- Day 3. Freeze the map. Any later change needs a written reason.
- Day 4 and 5. Build the first section, and fetch every mapped path against it.
Acceptance: the inventory is done when
- the union count is recorded, with all three sources named
- every path has exactly one disposition
- every move and retire names its target
- the map is frozen, with a date
- a script can fetch every path and print the status and the final URL
Troubleshooting
| Symptom | Likely cause | What to do |
|---|---|---|
| A path appears in no list | It was never linked and never indexed | Give it a disposition anyway |
| Two people disagree on one path | The map was never frozen | Freeze it, then change it with a reason |
| A redirect lands on a redirect | The target was retired later | Point the old path at the final page |
| Search Console shows a drop after launch | Redirects missing for pages with impressions | Compare the map against the impressions list |
| The new site serves a different slash form | Host and build disagree | Fix one of them before launch |
Limits
Parity is about paths and content, not about the design that replaces them.
A migration also changes hosting and deployment. Expect the first deploy to be the least interesting and the most instructive part of the week.