Migration & Replatform9 min read

How Long Does a Legacy CMS Migration Take? Sizing a Replatform to Structured Content

Most legacy CMS migrations miss their first committed date for the same reason.

Published November 12, 2026

Most legacy CMS migrations miss their first committed date for the same reason. The team sized the project by page count, then found mid-build that half the content needed remodeling, three integrations were undocumented, and every locale had drifted. Realistically, a small, clean estate moves in weeks, and a multi-market DXP estate takes one or more quarters. Remodeling and integrations account for that spread more than content volume does. In Sanity, scripted NDJSON imports and code-defined migrations make the content move repeatable, so the timeline goes into decisions rather than copy-paste.

A slipped cutover is expensive. It means paying for two platforms longer than planned, extending a content freeze that stalls campaigns, and asking editors to publish in two systems at once while leadership loses confidence in the program.

This guide doesn't give you a single number. It gives you a sizing method you can apply to your own estate, shows which phases can overlap, explains how phased rollouts bring the first business value forward, and ends with the questions to answer before a date goes into a steering-committee deck.

What drives the timeline of a legacy CMS migration?

Five factors drive how long a legacy CMS migration takes: content volume and cleanliness, how much content is remodeled versus moved as-is, the number of integrations, localization, and the scope of the frontend rebuild. Once transforms are scripted, volume matters least of the five, because a script that moves 500 documents moves 50,000 with the same logic. Cleanliness matters more. If body copy lives in HTML blobs with inline styles, embedded tables, and author-specific shortcodes, every pattern needs its own parsing rule, and each pattern found late adds days.

Remodeling is usually the largest swing factor. A lift-and-shift that reproduces the old page templates is faster to execute, but it carries the old structure forward, including fields nobody uses. Remodeling into structured content, such as separating a product description from its specifications or a press release from its boilerplate, takes design time up front. That time is repaid in every channel the content later serves.

Integrations are the most commonly underestimated driver. A legacy DXP such as Adobe Experience Manager or Sitecore often sits at the center of commerce, search, personalization, analytics, and DAM connections. Some were built years ago by people who have since moved on. Each connection needs an owner, a replacement plan, and a test.

Localization multiplies everything. Ten markets with independent translation histories aren't one estate times ten. They're ten estates, each with its own gaps, fallback rules, and legal review paths. Frontend rebuild scope sets the floor: if the migration also replaces a monolithic templating layer with a new frontend, design and build often take longer than the content move itself.

For a rough reference point, partner material describes simple replatforms in weeks. A G2 implementation-partner listing describes a typical four-week Sanity migration: discovery, content migration, core build, and then stabilization with editor training. Treat that as a floor for small, clean estates, not a promise for an enterprise DXP.

How do you size a migration against your own content estate?

To size a migration, work through five steps in order and put an estimate on each: content inventory, mapping to the new schema, scripted transforms, parallel runs, and cutover. Instead of one gut-feel date, you get a sum of smaller estimates you can test.

1. Content inventory. Export a count of every content type with its document volume, last-modified dates, locales, and inbound references. Flag content nobody has touched in two years as a candidate for archiving instead of migrating.
2. Mapping to the new schema. For each legacy type, decide whether it maps one-to-one, splits into several types, merges with another, or is retired. Every split or merge is a remodeling decision that needs a business owner.
3. Scripted transforms. Write code that reads the legacy export and outputs documents in the target shape, including rich text conversion, asset references, and links. Estimate this step by pattern count, not page count.
4. Parallel runs. Import into a non-production environment, validate, fix the script, and repeat until error counts approach zero. Editors and QA review real migrated content during this loop.
5. Cutover. Freeze legacy publishing, run the final import, switch routing, and keep the legacy system read-only for a defined rollback window.

The inventory step usually changes the estimate most. Teams often find that a large share of their pages are duplicates, expired campaigns, or orphaned drafts. Removing them before mapping shortens every later step. Mapping is where governance comes in: legal, brand, and regional owners have to approve what the new schema keeps and what it drops.

For step 3, count the distinct source patterns, such as a hero component, a legacy table, or a shortcode for embedded video, and give each a fixed scripting cost. That turns an open-ended question into a list a project manager can track, and it shows where messy content will cost time before anyone commits to a date.

Page count is the wrong unit

Migration effort grows with the number of distinct source patterns and remodeling decisions, not the number of pages. A script that converts one legacy component handles 500 or 50,000 instances with the same logic. A 50,000-page estate built from a few clean templates can move faster than a 5,000-page estate full of hand-built layouts.

How does schema-as-code shorten the schema mapping phase of a migration?

Schema-as-code shortens mapping because the target schema lives in a repository. Engineers can review it, diff it, and change it in minutes instead of reconfiguring it through an admin interface. In Sanity, schemas are defined in code, versioned, and kept in source control next to the frontend that renders them. During a long migration, the content structure and the application that depends on it can't quietly drift apart.

The contrast with legacy DXPs is specific. In Adobe Experience Manager and Sitecore, schemas are built and managed in the platform and versioned through a package manager, not kept in source control with application code. Both platforms have real strengths, including deep approval workflows and mature governance. But changing a content structure during migration means coordinating configuration changes across environments, either by hand or through package deployments.

Mapping is iterative. The first draft of a schema rarely survives contact with real content. A field assumed to hold one value turns out to hold lists in some records, or a region field is free text in one market and a fixed list in another. When the schema is code, each correction is a pull request that moves from development to staging to production with the rest of the code, and `sanity schemas validate` checks it along the way. Because schemas are code, they also work with AI coding tools such as Copilot and Cursor, which can draft type definitions from a sample legacy export for an engineer to review.

Every plan needs one caveat: changing a schema doesn't change existing content. If the schema evolves after an import, the documents already in the Content Lake need a migration to match. This actually helps planning, because the cost of each late schema change becomes visible.

This is the Model your business pillar in practice. Sanity, the AI Content Operating System and the intelligent backend for companies building AI content operations at scale, treats the schema as a description of how the business works rather than a set of page templates. Remodeling decisions made during migration therefore carry forward into every channel the content serves later.

How do scripted imports and Sanity migration tooling reduce manual effort?

Scripted imports cut manual effort because the migration becomes a program you can rerun, not a copy-paste project that has to be right the first time. Copy-paste effort grows with page count and introduces errors nobody can trace. A script grows with the number of source patterns and produces the same output on every run.

Sanity's recommended import route is the CLI command `sanity datasets import`. It reads newline-delimited JSON (NDJSON), one document per line, and each document needs a `_type`. During the import, all references are set to weak and switched to strong once every document is in place, so documents can load in any order. You no longer have to load authors, then categories, then articles in dependency order. Assets come along through the `_sanityAsset` property, which points at a source URL.

Three flags make repeated runs practical. `--replace` overwrites documents from an earlier pass as long as their `_id` values stay stable, so you can fix the transform script and run it again. `--missing` creates only the documents that don't exist yet, which suits incremental loads of new content. `--allow-failing-assets` keeps the import running when some legacy asset URLs return 404s and leaves you a list to chase instead of a failed run.

Once content is in the dataset, transforms are also code. `sanity migrations create` sets up a migration defined with `defineMigration`, using helpers such as `setIfMissing`, `append`, and `unset`. `sanity migrations run` does a dry run by default and writes changes only with `--no-dry-run`. The `--concurrency` setting (1 to 10) controls throughput. Sanity's docs list this exact case as a use: you've imported content from another CMS and want to improve its structure.

`sanity documents validate` then checks every document against the schema. That gives you a real count of remaining cleanup work instead of a guess, and you can track the count week over week until cutover.

ℹ️

Run validation explicitly after every import

Validation runs in the Studio, not on API or CLI imports, so an import can load documents that break the schema. Imports can also trigger webhooks and Functions. Disable webhooks before a bulk load, then run `sanity documents validate` to see how many documents still fail before anyone schedules cutover.

Which phases of a CMS migration can run in parallel?

Schema design, transform scripting, and frontend build can run in parallel once the schema stabilizes. Most of the calendar time you recover comes from that overlap. Inventory and the first mapping pass have to come first, because every later workstream depends on knowing which content types exist. After that, the work splits into three streams.

The content stream writes transform scripts and reruns them against a non-production dataset. The frontend stream builds templates against the stable schema, using migrated sample content instead of placeholder text, which surfaces layout problems early. The integration stream replaces commerce, search, analytics, and DAM connections one at a time. The trigger for splitting is a stable schema, not a perfect one. Once the core types are agreed, small field changes can be handled by a migration script instead of blocking every team.

Sanity's environment model supports this overlap. Schema and code move up from development to staging to production. Content moves down: teams copy production content into development and staging datasets so they test against real documents. The documented sequence is to dry-run a migration on staging, apply it there, test, and only then apply it to production. Blueprints describe the resources each environment needs in a file kept next to the application code, so a new staging environment can be reproduced instead of rebuilt by hand.

Parallel runs also need a way for non-engineers to review the work. The Presentation Tool previews drafts or a selected release in the real frontend, so regional editors and legal reviewers can check migrated content in context before it goes live. Content Releases, available on Enterprise plans, group documents in production so they can be previewed and published together. That suits a cutover where a whole section has to switch at once.

The final import and the cutover shouldn't overlap with anything else. If a last load runs while editors are still publishing in the legacy system, edits get lost. A short, announced content freeze before the final import keeps that boundary clean and makes the rollback window easy to define.

How do phased or market-by-market rollouts shorten time to first value?

Phased rollouts shorten time to first value by putting part of the estate live on the new platform weeks or months before the full migration ends. The team doesn't wait for one big-bang cutover at the end of a long program. It ships a bounded slice, learns from real traffic and real editors, and applies those lessons to the next slice.

The most common way to slice is by content type. Webstacks, a Sanity agency partner, describes moving Braze off Craft CMS, and Gong and Klaviyo off WordPress, in phased launches: core pages first, then the blog and localized content. Core pages are few, high-value, and usually the most heavily redesigned, so they deserve the remodeling effort first. Long-tail content such as blog archives follows once the transform scripts are proven.

The enterprise version is a market-by-market rollout. A multi-market organization picks a pilot market with manageable content volume and a willing local team, migrates it end to end, and uses the result as the template for every other market. The pilot exposes localization gaps, translation-vendor handoffs, and regional approval paths while little is at stake. Studio Workspaces let several brands or markets work in one Studio, so later markets join an existing setup instead of a new one.

Phasing has costs that belong in the estimate. Running two platforms at once means paying both licenses for a period, maintaining routing rules that send some URLs to the new frontend and others to the legacy one, and asking some editors to work in both systems. These costs are usually smaller than the risk of a single cutover, but they aren't zero.

This is where the Power anything and Automate everything pillars come in. Once the first slice is live, Functions can handle the repetitive work in later phases. They run TypeScript or JavaScript on Sanity's infrastructure, react to document create, update, and delete events, read and write the dataset, and call external services. That makes them a fit for translation handoffs, compliance checks, and enrichment after import as each new market comes online.

What questions should you answer before committing to a migration date?

Before you commit to a migration date, answer the ten questions below. Any question the team can't answer is a schedule risk and should get contingency time in the plan.

1. How many documents exist per content type, and how many have changed in the last two years?
2. What share of body content is structured fields, and what share is HTML blobs, shortcodes, or embedded markup?
3. Which content types will be remodeled, and who approves each decision?
4. How many distinct source patterns do the transform scripts have to handle?
5. Which integrations depend on the legacy system, and who owns each replacement?
6. How many locales exist, and do they share one structure or differ by market?
7. Is the frontend being rebuilt, redesigned, or reused as-is?
8. Which approval and compliance steps does migrated content have to pass before it goes live?
9. What is the rollback plan, and how long will the legacy system stay read-only?
10. Which slice ships first, and what counts as first value for the business?

Questions 2, 3, and 5 move the date the most. A clean estate with light remodeling and few integrations lands at the short end of any range. HTML-heavy content, a full remodel, and a dozen undocumented integrations add months, whatever the document count.

Published examples show the spread, though they're partner or customer claims, not Sanity-verified benchmarks. Mux moved 128 Ghost posts into Sanity over a couple of months, converting HTML into Portable Text about 10 posts at a time. Content cleanup set that pace, not volume. At the larger end, Multidots reports moving eight Sitecore sites in four months, though to WordPress VIP rather than Sanity. That still shows a scripted migration of a large estate can finish within a quarter or two.

A date built from these answers holds up in a steering committee because every week in it maps to a named driver. A date built from page count alone is the one that slips.

Migration effort compared: Sanity vs AEM, Sitecore, and Acquia Drupal

FeatureSanityAdobe Experience ManagerSitecore (XM/XP/XM Cloud)Acquia Drupal
Defining the target schema during mappingSchemas are defined in code and kept in source control with the frontend. Corrections ship as pull requests, and `sanity schemas validate` checks them.Schemas are built and managed in the platform and versioned through a package manager, not source-controlled with application code. Changes move between environments by package deployment.Templates are built and managed in the platform and versioned through a package manager. Mature and well understood, but changes are coordinated across environments, not in one repository.Content types are configured in the admin UI and can be exported as configuration files kept in Git. This works well, but keeping environments in sync takes team discipline.
Scripted bulk import into the platform`sanity datasets import` loads NDJSON. References load as weak and switch to strong, so documents can load in any order, and `--replace` reruns corrected passes.Content packages, APIs, and partner tooling support bulk moves. This is capable and well documented, but turning content into new structures usually needs custom development.Programmatic import through Sitecore APIs and partner frameworks is well established. Mapping content into new templates usually relies on custom code written by the implementation team.The Migrate API is a mature, plugin-based import framework with source, process, and destination stages. Complex legacy sources usually need custom plugins.
Restructuring content after import`sanity migrations run` applies code-defined `defineMigration` transforms as a dry run by default. `sanity documents validate` then counts the remaining schema errors.Restructuring after import is usually done with custom scripts or workflows. It works, but each transform is bespoke development work that has to be scheduled and tested.Restructuring and automation across systems often need custom code. It's achievable, with the effort falling on developer time rather than configuration.Restructuring means rerunning migrations with updated process plugins or writing update hooks. This is flexible but depends heavily on developers.
Parallel runs across environmentsSchema moves up from dev to staging to production, and production content is copied down for testing. Blueprints define each environment's resources in a versioned file.Mature development, stage, and production tiers, especially on AEM as a Cloud Service. Content is usually synced between tiers with packages.Established multi-environment practices with serialization and deployment pipelines. Reliable, but setting up environments is often infrastructure work.Standard dev, stage, and production workflows on Acquia hosting, with database and file copies moving down. Drupal teams know this pattern well.
Staged cutover with preview and sign-offContent Releases (Enterprise plans) group documents to publish together, and the Presentation Tool previews drafts or a selected release in the real frontend.A genuine strength: deep approval workflows, launches, and in-context authoring give reviewers a familiar path to preview and approve content before cutover.A genuine strength: robust workflow and publishing controls, plus in-context editing, give governance teams a well-proven review process.Content moderation and Workspaces modules support staged publishing and review. They're capable, though how much they can do varies from one build to the next.
Automation after migrationFunctions run TypeScript or JavaScript on Sanity's infrastructure when documents are created, updated, or deleted. They fit translation handoffs, compliance checks, and enrichment.The workflow engine and Adobe suite integrations automate many tasks inside the suite. Adapting those workflows to fast-moving teams takes major effort.Built-in workflows cover tasks inside the platform. Automation across systems often needs custom code and hosting the team has to maintain.Queues, scheduled jobs, and custom modules automate tasks with a lot of flexibility. The automation code runs on infrastructure your team operates or pays to host.

Ready to try Sanity?

See how Sanity can transform your enterprise content operations.