A Contentful export is only a baseline. Later edits can leave missing references, changed slugs, unpublished pages, and broken SEO signals after cutover.
Treat a Contentful → Sanity migration as a reversible production release. Include schema mapping, delta sync, delivery tests, and rollback.
Process overview
Run the migration in this order: assign owners, export a UTC baseline, map fields, import, validate, sync later edits, test delivery, cut over, and monitor.
Name owners and freeze rules
Assign engineering, editorial, SEO, and release owners. Record a baseline timestamp before the first export.
Use a 24–48 hour soft freeze for logged urgent edits. Then use a 30–90 minute hard freeze for final sync and traffic switching.
Account for automated jobs in the freeze plan. Include scheduled jobs, product feeds, form tools, and webhook-driven updates. They can change Contentful content without an editor.
Define pass and rollback rules
Launch only when counts match by type and locale. Required fields and references must also be complete.
Critical URLs must render correctly. Agree on rollback thresholds before the first import.
For a US production site with 500 to 5,000 entries, reserve 12 to 30 engineering hours for mapping, transformations, tests, and release work. Rich Text with embedded modules or three or more locales often adds 8 to 20 hours.
A baseline timestamp makes later changes easy to find. The next phase defines how every content field will survive the move.
Map models into Sanity safely
Create a field-level mapping matrix. It should show how each Contentful field becomes a Sanity document, object, reference, asset, or Portable Text block.
Build the mapping matrix
Record the source type, field ID, and locale behavior. Also record validation, target schema, transformation, fallback, and test result.
Keep each legacy Contentful entry ID. You need it for checks and delta updates.
The common mistake is mapping visible fields only. Hidden reference fields and validation rules can break editors after launch.
| Contentful source | Sanity target | Required test |
|---|
| Blog post entry | `post` document | Published count matches by locale |
| Linked author entry | Reference to `author` | No unresolved reference IDs |
| Rich Text field | Portable Text array | Links and embeds render |
| Asset | Sanity image or file asset | URL returns 200 and alt text exists |
Convert rich text and locales
Convert Rich Text to Portable Text. Keep links, embeds, assets, lists, marks, and custom modules.
Choose the locale structure with care, and treat unsupported nodes as import errors.
Production continuity flow
1. Baseline
Export at UTC time
2. Transform
Map IDs and blocks
3. Validate
Count and render
4. Delta
Sync later edits
5. Cutover
Watch and revert
Prepare the target Sanity project, dataset, API token scope, and Studio setup. Do this before running any conversion tool.
Keep the Contentful export as an unchanged baseline. Send test imports to a separate staging dataset.
Tools such as contentful-to-sanity can speed up a Sanity document import. They may also create useful starter schemas.
Generated schemas still need review. Check required fields, rules, document IDs, reference targets, and editor-facing names.
Pin the tool version and save import logs. This lets you rerun failed records the same way.
This takes longer with custom types, nested modules, or locale rules. A generic converter cannot infer those rules safely.
Contentful and Sanity use different content models.
Contentful often uses spaces, environments, content types, and locale settings. Sanity uses documents, objects, references, datasets, and an editable Studio.
Define drafts, scheduled publishing, validation, image data, and editor rights before cutover. Do not treat Sanity as a direct field-for-field replacement.
A reusable Contentful component can become a referenced Sanity document. Choose this when it needs separate reuse and publishing.
It can become an embedded object instead. Choose that when it always belongs to one page.
Clear mapping decisions protect CMS continuity. Next, test what visitors and search crawlers will actually receive.
Test URLs, SEO, and live delivery
Compare production and staging from the perspective of visitors and crawlers. Do not rely only on document counts or API responses.
Verify the frontend path
Test sitemap, analytics, and campaign URLs. Check status codes, redirects, canonicals, titles, metadata, robots, hreflang, structured data, and rendered content.
Capture screenshots for the top organic landing pages. These pages carry the highest SEO risk.
A successful API response does not prove a working page.
Rebuild events and permissions
Remap webhooks, cache purges, previews, publishing rights, uploads, and unpublish behavior. Then make a controlled staging edit.
Verify that the edit refreshes the frontend and CDN. Test both the publish and unpublish paths.
For teams serving the United States from US East or US West, measure cached and uncached pages separately. A CDN cache hit can be under 100 ms. An uncached server-side page can be much slower. Test both after every webhook change.
A working preview does not prove a working public cache. The cutover phase checks every late content change before traffic moves.
Block launch failures before cutover
During the hard freeze, sync every changed, published, unpublished, and deleted entry. Repeat parity tests before switching traffic.
Keep Contentful and the old frontend running until the observation period ends.
Use a release checklist
- Export the changed-entry queue from the baseline timestamp through freeze start.
- Import changed, newly published, unpublished, and deleted content into Sanity.
- Confirm zero broken references and zero missing required values in published documents.
- Run URL, canonical, redirect, sitemap, and screenshot checks against production candidates.
- Publish one controlled test edit and confirm webhook, frontend refresh, and CDN invalidation.
- Switch traffic only after engineering, SEO, and editorial owners sign off.
The final delta sync is where most launch gaps appear.
Watch the first release hour
Monitor 404s, 5xx errors, API failures, webhook failures, cache purges, response times, and locale-specific rendering. Watch for at least 60 minutes.
Review search coverage over the following days. Search engines need time to recrawl changed delivery paths.
⚠️ Do not revoke Contentful access or delete its environment until post-launch checks show stable delivery and editorial publishing.
Keep rollback ready until public delivery stays stable. The answers below cover the questions teams ask during planning.
What people ask
How do I migrate from Contentful to Sanity?
Export a baseline, map reviewed schemas, and import content. Sync later edits and validate assets, references, URLs, SEO fields, and public pages before switching traffic.
How do I avoid downtime during a CMS migration?
Keep the Contentful frontend live until the Sanity-backed version passes delivery tests. Keep a tested rollback path ready before traffic switching.
Does the Contentful to Sanity CLI migrate everything?
No. It can transfer content, but it does not recreate workflows, roles, previews, integrations, webhooks, or frontend cache behavior.
How do I know content is inconsistent after migration?
Compare counts, locales, required fields, assets, references, and rendered pages. Include at least the top 50 organic URLs.
Keep the release reversible
Keep Contentful and the prior frontend available during the observation period. A fast rollback protects visitors, editors, and search traffic.
- The essential point: an export is only a baseline, so later editorial changes need a delta sync.
- The essential point: schema mapping must preserve references, locales, validation, and Rich Text behavior.
- The essential point: SEO continuity needs public URL, canonical, redirect, sitemap, and rendering tests.
- The essential point: keep Contentful and the prior frontend ready until monitored production checks pass.
Further reading
If you want to learn more about this topic, these sources may interest you: