All posts
Platform migrations

Headless CMS Migration: How to Move Between Contentful, Sanity, Payload and Strapi

Headless CMS migration, done content-model first: how to move between Contentful, Sanity, Payload and Strapi with export scripts, mapping tables and validation.

By Mehdi Hassan11 min read

The short answer

A headless CMS migration moves your content model and content from one platform, such as Contentful, Sanity, Payload or Strapi, to another. Do it content-model first: redesign the schema, map every field, script the export, transform rich text and references, import in dependency order, then validate counts, links and rendered pages before cutover.

Key takeaways

  • Design the new content model before writing a single script. Copying the old one copies its mistakes.
  • Rich text and references are the hard parts; plain fields move in an afternoon.
  • Import in dependency order: assets, then referenced entries, then the entries that point at them.
  • Validate with counts, reference checks and rendered-page diffs, not by clicking around.
  • Run old and new CMS side by side until the front end has switched and editors have signed off.

How do you migrate content from one headless CMS to another?

You migrate content between headless CMSs in six stages: design the new content model, map old fields to new ones, export everything with scripts, transform rich text and references, import in dependency order, and validate before switching the front end. The method is the same whether you're moving from Contentful to Sanity, Sanity to Payload or Strapi to anything else.

Headless migrations are easier than website migrations in one way: your front end and URLs don't have to change. They're harder in another: every CMS stores rich text, references, locales and assets differently, and that's where content gets lost. This guide is the general method. The pair-specific guides linked below cover the quirks of each move, starting with Contentful to Sanity and Contentful to Payload.

Stage

Output

Who owns it

Content model

New schema, reviewed by editors

Developer and content lead

Field mapping

A sheet mapping every old field to a new one

Developer

Export

Raw JSON or NDJSON of entries and assets

Script

Transform

Converted rich text, references and locales

Script, reviewed by a developer

Import

Content in the new CMS, in dependency order

Script

Validate and cut over

Counts, diffs, editor sign-off, front end switched

Developer and editors

Why do teams switch headless CMS?

Teams switch headless CMS for four reasons: pricing jumps, editing experience, the wish to self-host, and developer experience. Pricing is the most common trigger, and it usually arrives as a tier boundary rather than a gradual increase.

Our research found that Contentful's tier jumps, such as the 25-content-type ceiling on a smaller space tier noted in Pagepro's migration write-up, push teams toward Sanity or Payload. Locales and seats create similar step changes in other platforms. Editing experience is the second trigger: editors who want a customizable studio or visual editing. The third is control: teams that want content in their own database, which is why self-hosted options like Payload and Strapi come up. For a side-by-side view, read Contentful vs Sanity vs Payload vs Strapi.

  • Pricing tier boundaries: content types, locales, seats or API usage crossing a plan limit.
  • Editing experience: editors need a better studio, previews or a visual editor.
  • Ownership and hosting: content should live in your database, on your infrastructure.
  • Developer experience: a typed, code-defined schema that lives with the front end.

What is a content-model-first CMS migration?

A content-model-first migration designs the new schema before moving any content, instead of recreating the old schema field for field. It's the single decision that most improves the result, because every CMS accumulates content types nobody uses, duplicated fields and workarounds for the old platform's limits.

Start by listing every content type with its entry count and last edit date. Merge types that differ only by a flag, delete types with no entries, and replace workaround patterns with the new CMS's native features, such as Payload's blocks field or Sanity's Portable Text custom blocks. Then review the draft schema with the people who edit content every week. Our guide to content modeling for CMS migrations covers this in depth, and content modeling 101 explains the basics for a SaaS site.

Migrate the content you need into the model you want, not the model you had.

How do you map content types between Contentful, Sanity, Payload and Strapi?

You map content types by matching each platform's equivalent concept, then writing down every field-level difference. The concepts line up closely; the details, especially rich text and localization, don't.

Concept

Contentful

Sanity

Payload

Strapi

Content type

Content type

Document type

Collection

Collection type

Singleton

Single entry by convention

Singleton document

Global

Single type

Rich text

Rich text JSON document

Portable Text

Lexical JSON

Blocks or Markdown

Flexible sections

References to section entries

Array of objects

Blocks field

Dynamic zone

References

Link fields

Reference fields

Relationship fields

Relations

Localization

Per-field locales

Field or document level, by plugin

Per-field, localized flag

Per-entry locales via i18n

Assets

Assets with CDN URLs

Image and file assets

Upload collections

Media library

Build the field mapping as a spreadsheet with one row per old field: old type, old field, new type, new field, transform needed and notes. It becomes the spec for your scripts and the checklist for validation. Check each platform's current docs for field types before you finalize it, since CMSs add field types between versions.

How do you export, transform and import headless CMS content?

You export with the old CMS's tooling or API, transform with a script you own, and import with the new CMS's API or import tool. Keep the three steps separate, so you can re-run the transform without hitting either API again.

  1. Export everything

    Use the platform's export tool or API to pull entries, assets, locales and drafts into JSON files. Contentful has a CLI space export; Sanity exports datasets as NDJSON.

  2. Freeze or log changes

    Agree a content freeze for the cutover window, or log every edit made after export so you can replay it.

  3. Transform fields

    Map plain fields directly. Convert rich text to the new format, resolve references to new IDs and reshape locales.

  4. Download and re-upload assets

    Download every image and file, upload them to the new CMS, and record a map of old asset IDs to new ones.

  5. Import in dependency order

    Import assets first, then entries that others reference (authors, categories), then the entries that point at them.

  6. Make the script repeatable

    Use stable IDs so a second run updates rather than duplicates. You'll run it several times before cutover.

For the general mechanics of exporting, cleaning and importing between any platforms, including non-headless ones, see CMS content migration. Coming from Webflow, start with exporting Webflow CMS content.

How do you migrate rich text and references between CMSs?

You migrate rich text by converting the old format into the new one node by node, and references by importing referenced entries first and rewriting IDs from a lookup table. These two steps take most of the engineering time in any headless CMS migration.

Each CMS stores rich text as structured data with its own vocabulary: Contentful's rich text is a JSON tree of nodes, Sanity uses Portable Text blocks with marks and annotations, and Payload's default editor stores Lexical JSON. Headings, paragraphs, lists, links and bold text map cleanly. Embedded entries, inline references and custom components need a decision for each one.

How to handle embedded entries inside rich text

Embedded entries, such as a code sample, a call-to-action box or a product card dropped into an article, are the usual casualties.

First, list every embedded entry type in use by scanning the exported rich text for embed nodes. Second, define a matching custom block in the new CMS: a Portable Text object type in Sanity, a Lexical block in Payload, or a component in Strapi. Third, have the transform script convert each embed node into that block, carrying its reference through the ID lookup table.

Then render a sample of articles with each embed type and compare them against the old site. If an embed type appears in only a handful of articles, it can be cheaper to rewrite those by hand.

References work best with a two-pass import. In the first pass, create every entry with its plain fields and record old ID to new ID. In the second pass, patch in the references using the lookup. This avoids failures when two entries point at each other. For WordPress sources, where content is HTML, WordPress to Sanity or Payload covers HTML conversion.

How do you validate a headless CMS migration?

You validate a headless CMS migration with automated checks first and human review second: entry counts per type and locale, reference integrity, slug parity and rendered-page comparisons. Clicking through a few pages finds the obvious problems and misses the ones that matter.

  1. Counts: entries per type and per locale match the export, minus anything you chose to drop.
  2. References: no reference points at a missing entry, and no entry lost its references.
  3. Slugs: every published slug exists in the new CMS, so URLs on the front end don't change.
  4. Assets: every image in fields and in rich text resolves to the new CMS's storage.
  5. Rendered diffs: render a sample of pages from old and new content and compare them visually.
  6. Editor sign-off: editors check their own content types and the editing workflow, including previews.

Previews deserve their own test, because they're often what editors care about most. If the new setup includes visual editing, check it before cutover with our guide to live preview in headless CMS setups.

Which headless CMS migration are you planning?

Pick your pair below. Each guide covers that move's specific triggers, tooling and data conversion, on top of the general method in this hub.

Moving from

Moving to

Read

Contentful

Sanity

Contentful to Sanity migration

Contentful

Payload

Contentful to Payload migration

Sanity

Payload

Sanity to Payload migration

Strapi

Payload

Strapi to Payload migration

Prismic or Storyblok

Sanity

Prismic or Storyblok to Sanity

WordPress

Sanity or Payload

WordPress to Sanity or Payload

Webflow CMS

A headless CMS

Webflow CMS to headless CMS

Framer CMS

A headless CMS, keeping Framer

Framer to headless CMS

Not sure yet

Comparing options

Contentful vs Sanity vs Payload vs Strapi

If you're new to headless architecture altogether, read headless CMS explained for non-developers first. Commerce teams moving product content should see migrating a Shopify theme store to headless.

How long does a headless CMS migration take, and what does it cost?

A headless CMS migration's length and cost scale with content types, rich text complexity and locales, so a small, clean dataset is a short project and a large multilingual one is a long one. Our research found agencies quoting $1.5k to $25k for website migrations by size, and £13k to £30k over 6 to 12 weeks for a WordPress to headless Next.js move, which includes a front-end rebuild.

Typical website migration quotes by size (our research)
$1.5k–$25k
Quoted for WordPress to headless Next.js (our research)
6–12 weeks
Designify retainer: ongoing design and development team
$6,000/mo

A CMS-to-CMS move with no front-end change sits at the lower end, because the work is the content model, scripts and validation. The drivers are content types, rich text complexity, embedded entries, locales and asset volume. A front-end rebuild at the same time is a much larger project, so decide whether you're changing one layer or two before you ask for quotes. For commerce stacks, see headless Shopify cost.

What mistakes break headless CMS migrations?

The mistakes that break headless CMS migrations are copying the old model, ignoring rich text embeds, hot-linking assets, skipping drafts and locales, and cutting over without editor sign-off. Each one is cheap to prevent and expensive to fix after launch.

  • Copying the old schema. You keep every workaround the old platform forced on you.
  • Ignoring embedded entries. Articles render with gaps where components used to be.
  • Hot-linking assets. Images break the day the old plan is cancelled.
  • Forgetting drafts and scheduled content. Editors lose unpublished work.
  • Flattening locales. Translations collapse into the default language or go missing.
  • No content freeze. Edits made during the migration window disappear at cutover.

Keep the old CMS running read-only until the front end has run on the new one for a few weeks and editors have confirmed nothing is missing. It's the cheapest insurance in the project.

Frequently asked questions

Can I migrate a headless CMS without changing my front end?
Yes, and it's the lower-risk way to do it. You rewrite the data-fetching layer to query the new CMS and keep components, routes and URLs the same. The content model can still improve, as long as the front end's queries map the new shape back to what components expect. Redesign separately, later.
Do I need a content freeze during a CMS migration?
You need either a freeze or a change log for the cutover window. Without one, edits made after the final export never reach the new CMS. Most teams run the scripts repeatedly in advance, then freeze editing for a short window, run the final import, validate and switch the front end.
Can AI help migrate CMS content?
AI coding tools are useful for writing export and transform scripts, generating field mappings and converting unusual rich text. They're less reliable for deciding what to keep, merge or drop in the content model. Use AI to speed up the scripting, and keep validation automated, since scripts are only as correct as their checks.
Should I migrate old content or start fresh?
Migrate content that earns traffic, links or sales, and leave the rest. An audit before migration usually finds outdated posts, duplicate pages and abandoned content types. Dropping them reduces script work and validation time. Redirect any dropped URL to its closest relevant page so you keep its search value.
What happens to my old CMS IDs after migration?
New platforms generate new IDs, so store the old ID as a field on each migrated entry. It makes the script repeatable, helps debug missing references and lets you trace any page back to its source. Remove the field later if you like, but keep it at least until the old CMS is retired.
Is self-hosting a headless CMS worth it?
Self-hosting is worth it when you want content in your own database, predictable costs and code-defined schemas, and you have developers to run it. It isn't worth it for a team without engineering time, because updates, backups and uptime become your responsibility. Hosted CMSs trade that work for a monthly bill.

· CEO & Design Director

Copywriter, designer and developer, and founder of Designify Studio. Over five years, 60+ projects across 14+ industries, for startups that have raised $300M+.

Want this done for you? Monthly retainer, $6,000.

Your ongoing design and development team, for products that keep shipping. $6,000, per month, flat fee. Book a free 30-minute call to see if it fits.

Schedule Call