Migrating a live website to a new content management system is one of those jobs that looks like a data transfer and turns out to be an exercise in risk management. The database part is usually the easy half. The hard half is that a working site has years of accumulated meaning attached to it — URLs search engines memorised, editors' habits, a content model that drifted far from whatever it was on day one.
Over the past years I've moved a few hundred sites — mostly news portals and online stores — off general-purpose, plugin-assembled CMS setups onto purpose-built platforms. Some of those migrations were clean. A few taught me things the hard way. This is the accumulated checklist, aimed at anyone about to do their first serious one.
Why sites migrate at all
Nobody migrates a CMS for fun. The trigger is almost always one of four things, and it's worth naming yours honestly before you start, because it determines what "success" means.
Plugin sprawl. A site starts generic and grows domain-specific through add-ons: one plugin for the ticker, one for the photo gallery, one for the ad slots, one for the newsletter, three for SEO. Each one is maintained by a different party on a different release cadence. The site works, but nobody can predict what a routine update will break.
Performance under spikes. A general CMS with fifteen plugins executes a lot of code to render a page that is, semantically, one article. For a news site where a single story can bring 40× normal traffic in ten minutes, that overhead stops being academic.
Editorial friction. This is the one clients articulate least well and feel most. If publishing a story with a photo gallery, a source credit, a related-articles block, and an agency attribution takes eleven clicks across four screens, your newsroom will invent workarounds, and your data model will slowly fill with those workarounds.
Cost of ownership. Ten commercial add-on licences plus a maintenance retainer, renewed annually, forever.
Write your trigger down. If it's performance, you need before/after numbers. If it's editorial friction, you need to time the actual publishing workflow before and after. A migration that can't be measured will be judged on vibes, and vibes after a migration are always bad for the first two weeks.
The part everyone underestimates: URLs
Here is the single highest-risk element of any migration of an established site: the URL is not a detail, it's the asset.
A news site that has been publishing for eight years has tens of thousands of indexed URLs. Some carry external links. Some rank on page one for terms the business depends on. Every one of them that returns a 404 after cutover is value thrown away, and search engines are considerably slower to give it back than they were to take it.
So before touching anything else:
Export the complete URL inventory. Not the sitemap — the sitemap is what the old CMS thinks exists. Pull the real list from server access logs (every distinct path with a 200 in the last 12 months), from the search console's indexed-pages report, and from the database. Union all three. The gap between the sitemap and the logs is routinely 20–30%, and it's where the old, still-ranking content lives.
Classify it. Articles, category pages, tag pages, author pages, static pages, media files, feeds, pagination, and the long tail of oddities — print views, AMP variants, tracking-parameter duplicates, dated archive pages.
Decide the target URL scheme once, on purpose. If the new system can preserve the existing pattern, preserve it. Redesigning URLs "while we're in there" doubles the risk of the migration for aesthetic gain. If you genuinely must change the scheme, you now owe every old URL a permanent redirect.
Build the redirect map as data, not as rules. Regex rules feel elegant and fail silently on the exceptions. A generated lookup table of old path → new path, produced from the actual inventory, is boring and verifiable. You can test all 40,000 entries automatically; you cannot test a regex against the URLs you forgot existed.
Verify with a crawl, not a spot check. After cutover, crawl the full old inventory against the live site and assert: status is 301 (not 302, not 200-with-different-content), the destination resolves 200 in one hop, and no chains or loops exist. Redirect chains are where migrations quietly leak ranking.
The rule I'd tattoo on a junior developer: a migration is not done when the content is moved; it's done when the old URLs still work.
Content models never map one-to-one
The second discovery of every migration is that the old content model is not what the documentation says. It's what editors made it.
You will find, reliably:
- A "category" that is actually used as a workflow flag ("Ready", "Legal check").
- Three tags that mean the same thing with different capitalisation, plus one with a trailing space.
- HTML pasted into a plain-text summary field, because the summary needed a line break in 2019.
- Images referenced by absolute URL to the old domain, inside article bodies.
- A custom field that is empty on 90% of records and load-bearing on the other 10%.
Two practical responses. First, profile before you map. For every field you intend to migrate, run the actual distribution: how many distinct values, how many nulls, the longest value, how many contain HTML, how many contain absolute URLs. Ten minutes of profiling prevents a mapping decision built on an assumption.
Second, decide explicitly what not to migrate. Migration is the one moment when dropping dead weight is cheap. Fifteen years of unused tags, an abandoned events module, a decade of spam comments — carrying them forward means maintaining them forever. Just make the decision consciously and record it, rather than discovering the loss in month three.
The transformation itself I'd keep as a repeatable, re-runnable script, never a hand-edited dump:
read source record
→ normalise (trim, fix encoding, resolve relative media paths)
→ map fields to target model
→ validate (required fields present, slug unique, dates sane)
→ write, or write to a rejects file with the reason
Re-runnable matters more than it sounds. You will run the migration many times — against a copy, into staging, into a rehearsal, and finally for real. If the process is a script that takes the source and produces the target from scratch, every run is identical and every fix is permanent. If it's a script plus "and then I manually fixed those 40 rows", you have no repeatable process, and the final run will differ from the rehearsal in ways you can't see.
Media is where the disk space and the surprises are
Content rows are small. Media is not, and it's messier:
- Files referenced in article bodies by absolute URL — these break the moment the domain or path changes and must be rewritten during transformation.
- Orphan files: uploaded, never referenced. Often 30–50% of the media directory.
- Referenced files that don't exist. Someone cleaned up a folder in 2021.
- Generated thumbnail variants in a naming scheme the new system doesn't share.
- Filenames with non-ASCII characters and spaces, which behave differently across filesystems and web servers.
Before the migration, produce two lists: referenced-but-missing (fix or accept — these become broken images), and present-but-unreferenced (usually skip). Never regenerate thumbnails on first request under production traffic; pre-generate them during the migration, or your launch-day load test will be an unintentional one.
Rehearse the cutover, then rehearse it again
The cutover is a sequence of steps under time pressure, which is exactly the condition in which people improvise. So write it down as a runbook with times, owners, and — for each step — the answer to "how do we undo this?"
A workable shape:
- T-7 days: full migration into staging with production data. Editors do real work in it for a week. This is the only reliable way to surface editorial-workflow problems, and it's the step most often skipped for schedule reasons.
- T-2 days: dry run of the entire cutover against staging, stopwatch running. You now know how long the real one takes. It's always longer than the estimate.
- T-1 day: DNS TTL lowered. Content freeze agreed with the newsroom, in writing, with a named person responsible.
- T-0: final delta sync (only content created since the main import), switch, smoke tests, redirect crawl.
- T+1 hour: the checks below.
- T+7 days: daily monitoring of crawl errors and index coverage.
Pick your window by traffic, not by convention. For a news site the quiet hour is usually early morning local time — but check the actual analytics, and check the editorial calendar. Cutting over the night before a major scheduled news event is a self-inflicted wound.
Define the rollback before you need it. What's the trigger (error rate above X, homepage down more than Y minutes)? Who decides? How long does reverting take? A rollback plan that takes four hours isn't a rollback plan; it's a wish. In practice this usually means: keep the old stack running and untouched, switch at the DNS or proxy layer, and don't decommission anything for at least a fortnight.
What to check in the first hour, and the first month
Immediately after cutover, in this order:
- Homepage and a sample of article pages return 200 with the right content.
- The redirect crawl passes across the full old-URL inventory.
- Feeds and the sitemap are valid and reachable; submit the new sitemap.
-
robots.txtis the production one. (Staging'sDisallow: /reaching production is a classic, and it is genuinely expensive.) - Canonical tags and structured data render correctly on article pages.
- Search: does querying an old, well-known headline return it?
- Publishing works end to end — an editor publishes a real story with an image while you watch.
- Analytics and any ad slots are firing.
Then over the following weeks, watch crawl errors (a slow rise in 404s means the URL inventory had gaps), index coverage (a drop means something is deindexing content — check canonicals and robots directives first), server response time under real traffic, and the numbers that justified the migration in the first place.
Expect a short dip in traffic. A one-to-two week wobble while search engines re-crawl is normal even on a clean migration. A sustained four-week decline is not a wobble; it's a bug, and it's nearly always URLs, canonicals, or robots directives — in that order of likelihood.
The things I'd tell myself before the first one
- Preserve URLs. Everything else is negotiable.
- Profile the real data before mapping it. The schema is a claim; the data is the fact.
- Make the migration a re-runnable script, never a manual fix-up.
- Rehearse with editors, not just with developers. They will find in one afternoon what a test suite won't find in a month.
- Keep the old system alive and reversible for two weeks. It costs a little hosting and buys a lot of sleep.
- Measure the thing you migrated for. Otherwise the only feedback you'll get is the first complaint.
None of this is exotic. A CMS migration is mostly the discipline to do unglamorous inventory work before the interesting part, and the honesty to define in advance what "it went wrong" looks like.
If you've done a large migration, I'm curious what bit you that isn't on this list — the failure modes seem to be endlessly inventive.
Top comments (0)