# How do you migrate from Contentful to Sanity?

Reviewed by Martin Dejnicki · facts verified 25 October 2026 · canonical: https://deploi.ca/sanity/migration/contentful-to-sanity

## Short answer

A Contentful to Sanity migration runs in three moves: convert the space, rewrite the schema as reviewed code, and import into a test dataset. Sanity's contentful-to-sanity tool exports the space and writes a schema file and a newline-delimited JSON (NDJSON) dataset ([Sanity plugin page](https://www.sanity.io/plugins/contentful-to-sanity), October 2026). Version 5.0.0 drops Rich Text tables ([converter source](https://github.com/sanity-io/contentful-to-sanity/blob/main/src/utils/contentfulEntryToSanityObject.ts), October 2026), so count yours first.

- **Official converter:** contentful-to-sanity 5.0.0, 13 March 2026. Exports a space, writes a schema file and NDJSON; skips Rich Text tables, and imports one locale unless you run the separate schema and dataset commands with --intl multiple ([Sanity, contentful-to-sanity Changelog](https://github.com/sanity-io/contentful-to-sanity/blob/main/CHANGELOG.md); [Sanity, contentful-to-sanity source: contentfulEntryToSanityObject.ts](https://github.com/sanity-io/contentful-to-sanity/blob/main/src/utils/contentfulEntryToSanityObject.ts); [Sanity, contentful-to-sanity source: command.ts](https://github.com/sanity-io/contentful-to-sanity/blob/main/src/cli/command.ts))
- **Contentful records:** 10,000 per environment on Lite. Lite's Starter Space allows 2 environments, each with its own 10,000 records of entries plus assets; Sanity counts documents across every dataset ([Contentful, Pricing](https://www.contentful.com/pricing/); [Contentful, Environments](https://www.contentful.com/help/faq/environments/); [Contentful, Spaces](https://www.contentful.com/help/spaces/))
- **Sanity Growth:** $15 per seat a month, 25,000 documents. Unlimited content types and locales, 2 datasets; documents count across every dataset, drafts included, with no overage allowed ([Sanity, Plans that scale with you](https://www.sanity.io/pricing); [Sanity Docs, Plans and payments](https://www.sanity.io/docs/platform-management/plans-and-payments))
- **Locale multiplier:** 100 documents in 3 languages become 400. Document-level localization stores one document per language plus one translation.metadata document; field-level keeps one ([Sanity, @sanity/document-internationalization README](https://github.com/sanity-io/plugins/blob/main/plugins/%40sanity/document-internationalization/README.md); [Sanity Docs, Localization](https://www.sanity.io/docs/studio/localization))

## Deploi's call

Plan a Contentful to Sanity migration around what the converter won't do: Rich Text tables, JSON fields, archived entries, extra locales and every front-end query. Count documents the Sanity way, with drafts, every locale and every dataset, before you commit, because that number decides between Growth and Enterprise. Whether to leave Contentful at all is a separate decision; make it first.

**PHASE: Move from Contentful to Sanity in phases when**

- Your Contentful organization runs several spaces or front ends, so each one can move, launch and be checked while the rest stays on Contentful.
- Your front end calls Contentful's Delivery or GraphQL APIs (application programming interfaces) throughout, because rewriting those queries in GROQ (Graph-Relational Object Queries) is the largest line item in Deploi's judgment, and a phase keeps each rewrite small enough to test.
- Editors keep publishing during the move, so you re-export and re-import each phase's content just before it launches.

**MIGRATE: Move a Contentful space to Sanity in one cutover when**

- One space feeds one front end, so a single launch replaces every Contentful query.
- A test import matches your Contentful counts per content type, and the documents, with drafts and every locale, fit Sanity Growth's 25,000, or 50,000 with the $299 a month add-on, as of October 2026.
- Few Rich Text fields hold tables, because the converter drops tables and each one is rebuilt by hand.

## What does Sanity give you to migrate from Contentful?

Sanity gives you two aids to migrate from Contentful, and neither runs the move end to end. The contentful-to-sanity command-line interface (CLI) turns a space export into a schema file and a newline-delimited JSON (NDJSON) dataset ([Sanity plugin page](https://www.sanity.io/plugins/contentful-to-sanity), October 2026). Sanity's migration skill for AI (artificial intelligence) agents has a Contentful guide ([Sanity on GitHub](https://raw.githubusercontent.com/sanity-io/agent-toolkit/main/skills/sanity-migration/SKILL.md), October 2026), and Sanity calls the skill "agent-scaffolded, not fully automated" ([Sanity Blog, What's new in August](https://www.sanity.io/blog/august-releases-2026), October 2026).

**Sanity's two Contentful migration aids, and what each leaves to you**

| Aid | What it does | What it leaves to you |
| --- | --- | --- |
| contentful-to-sanity CLI | Converts a space export into a schema file and an NDJSON dataset | Rich Text tables, JSON fields, archived entries and extra locales |
| Migration skill, Contentful guide | Helps an AI agent plan and write migration scripts | The decisions, running the scripts and checking the result |

Sources: [Sanity, Contentful to Sanity plugin](https://www.sanity.io/plugins/contentful-to-sanity); [Sanity, contentful-to-sanity source: contentfulEntryToSanityObject.ts](https://github.com/sanity-io/contentful-to-sanity/blob/main/src/utils/contentfulEntryToSanityObject.ts); [Sanity, contentful-to-sanity source: command.ts](https://github.com/sanity-io/contentful-to-sanity/blob/main/src/cli/command.ts); [Sanity, contentful-to-sanity source: contentfulToDataset.ts](https://github.com/sanity-io/contentful-to-sanity/blob/main/src/helpers/contentfulToDataset.ts); [Sanity Blog, What's new in August](https://www.sanity.io/blog/august-releases-2026); [Sanity on GitHub, sanity-migration skill](https://raw.githubusercontent.com/sanity-io/agent-toolkit/main/skills/sanity-migration/SKILL.md). As of 25 October 2026.

Whether to leave Contentful at all is [a decision separate from the migration, with the case for staying](https://deploi.ca/sanity/migration/leaving-contentful), and so are [the points where each platform's price jumps to Enterprise](https://deploi.ca/sanity/compare/sanity-vs-contentful/pricing). Salesforce says it completed the purchase on 1 September 2026 ([Salesforce](https://www.salesforce.com/news/press-releases/2026/01/22/salesforce-signs-definitive-agreement-to-acquire-contentful/), October 2026); [what Salesforce ownership changes for Contentful customers](https://deploi.ca/sanity/migration/leaving-contentful/salesforce-ownership) has its own answer.

## How do Contentful content types, entries and references map to Sanity?

Each Contentful content type becomes a Sanity document type in code, each entry a document, and each Reference field a Sanity reference. The contentful-to-sanity converter also decides that slug editors become slug objects, Markdown becomes Portable Text unless you pass `--keep-markdown`, and JSON object fields become JSON strings ([converter source](https://github.com/sanity-io/contentful-to-sanity/blob/main/src/utils/contentfulEntryToSanityObject.ts), October 2026). When you rewrite the generated schema, merge types that were split to fit Contentful's 50-field cap ([Contentful data model](https://www.contentful.com/developers/docs/concepts/data-model/), October 2026).

**Contentful's model maps to Sanity almost one to one**

| Contentful | Sanity | What changes |
| --- | --- | --- |
| Content type | Document type in code | The schema lives in your repository |
| Entry | Document | A draft is a second document |
| Rich Text | Portable Text array | Tables need a table schema you declare |
| Asset | Image or file asset | Counts toward assets, not documents |
| Locale | Language field or array | Document-level or field-level per type |
| JSON object | String after conversion | Reshape into a typed object |

Sources: [Sanity Docs, Plans and payments](https://www.sanity.io/docs/platform-management/plans-and-payments); [Sanity Docs, Localization](https://www.sanity.io/docs/studio/localization); [Sanity, contentful-to-sanity source: contentfulEntryToSanityObject.ts](https://github.com/sanity-io/contentful-to-sanity/blob/main/src/utils/contentfulEntryToSanityObject.ts). As of 24 October 2026.

> **What the converter changes without asking**
>
> - Rich Text tables are skipped with a console warning ([converter source](https://github.com/sanity-io/contentful-to-sanity/blob/main/src/utils/contentfulEntryToSanityObject.ts)).
> - Archived entries import as published documents flagged `contentfulArchived` ([dataset helper source](https://github.com/sanity-io/contentful-to-sanity/blob/main/src/helpers/contentfulToDataset.ts)), so filter or delete them before launch.
> - One locale imports by default; `--intl multiple` works only with the separate `schema` and `dataset` commands ([converter command source](https://github.com/sanity-io/contentful-to-sanity/blob/main/src/cli/command.ts)).

## How does Contentful Rich Text become Portable Text?

Contentful Rich Text converts to Portable Text automatically for paragraphs, headings, lists, marks, links and embedded entries, but not for tables. Both are JSON trees: Contentful nests every node under one `document` root ([Contentful rich text docs](https://www.contentful.com/developers/docs/concepts/rich-text/), October 2026), and Portable Text stores an array of blocks, each holding spans that carry marks ([Sanity block content docs](https://www.sanity.io/docs/studio/block-content), October 2026). The contentful-to-sanity tool runs the `@portabletext/contentful-rich-text-to-portable-text` library, resolves embedded entries and entry links into Sanity references, turns horizontal rules into a break block, and drops table nodes ([converter source](https://github.com/sanity-io/contentful-to-sanity/blob/main/src/utils/contentfulEntryToSanityObject.ts), October 2026). Contentful's Rich Text field supports tables ([Contentful data model](https://www.contentful.com/developers/docs/concepts/data-model/)), so search the export for table nodes before you convert, because a warning scrolls past in a long run.

The converter drops tables, so rebuild each one yourself. Sanity's Portable Text Editor has built-in table editing from Studio v6.6.0, which is off by default and binds to a `table` schema you declare ([Sanity Docs, Configure the Portable Text Editor](https://www.sanity.io/docs/studio/portable-text-editor-configuration); [Sanity Blog, What's new in August](https://www.sanity.io/blog/august-releases-2026), October 2026); declare that schema and load each Contentful table into it. We built our own table block for deploi.ca, described in tables and citations in Portable Text. The Portable Text review covers the editor itself.

## How should Contentful locales map to Sanity localization?

Map each Contentful content type to Sanity's document-level or field-level localization by one test: do editors publish locales on different days? Contentful publishes all of an entry's locales at once by default; publishing one locale alone needs locale-based publishing, sold only on specific plans ([Contentful locale-based publishing](https://contentful.com/help/localization/locale-based-publishing), October 2026). Sanity's field-level localization keeps every language in one document but publishes all languages at once; document-level localization gives each language its own document that publishes independently ([Sanity localization docs](https://www.sanity.io/docs/studio/localization), October 2026). So per-locale publishing maps to document-level. Fallback locales don't migrate as a setting: in Sanity you write the fallback into each query with the `coalesce()` function of GROQ (Graph-Relational Object Queries), as the same docs show. The converter's `--intl multiple` mode writes the older `__i18n_lang` and `__i18n_refs` fields, which the current @sanity/document-internationalization plugin replaces with `translation.metadata` documents ([converter source](https://github.com/sanity-io/contentful-to-sanity/blob/main/src/utils/createIntlFields.ts); [plugin upgrade notes](https://github.com/sanity-io/plugins/blob/main/plugins/%40sanity/document-internationalization/docs/00-upgrade-from-v1.md), October 2026). The [Sanity localization review](https://deploi.ca/sanity/review/localization) rates both approaches.

> **Is Contentful localization all-or-nothing?**
>
> A Sanity comparison page, based on public docs and user reports as of March 2026, calls Contentful localization "all-or-nothing per content type" ([Sanity comparison](https://www.sanity.io/contentful-vs-sanity)). Contentful's docs enable locales per space and per field ([Contentful localization docs](https://www.contentful.com/developers/docs/tutorials/general/setting-locales/), October 2026), and on the plans that include locale-based publishing, one locale can be released at a time ([Contentful locale-based publishing](https://contentful.com/help/localization/locale-based-publishing)). Check which setting your environments use.

## What happens to Contentful environments, and how many Sanity documents will you need?

Contentful environments become Sanity datasets only for development and risky schema changes; routine staging happens inside the production dataset, as drafts on Growth. Sanity reserves a separate dataset for development and for changes that rename, remove or restructure content ([Sanity environments docs](https://www.sanity.io/docs/content-lake/environments), October 2026). The counting rule flips too: Contentful gives every environment its own 10,000-record limit on Lite's Starter Space ([Contentful environments FAQ](https://www.contentful.com/help/faq/environments/); [Contentful pricing](https://www.contentful.com/pricing/), October 2026), while Sanity counts every stored document, drafts included, across all datasets, with no document overage on Growth ([Sanity plans and payments](https://www.sanity.io/docs/platform-management/plans-and-payments), October 2026). So a full staging copy doubles your Sanity document count. Contentful's master alias maps to Sanity dataset aliases, which need Enterprise ([Sanity environments docs](https://www.sanity.io/docs/content-lake/environments)).

**A full Contentful Starter Space in 3 locales can outgrow Sanity Growth (Deploi arithmetic)**

| Sanity setup | Documents | Fits Growth |
| --- | --- | --- |
| Field-level, production only | 8,000 | Yes, under 25,000 |
| Field-level, production plus a full staging copy | 16,000 | Yes |
| Document-level in 3 locales, production only | 32,000 | Only with the $299 a month quota add-on |
| Document-level in 3 locales, plus a staging copy | 64,000 | No, above 50,000 |

Deploi arithmetic for 8,000 entries and 2,000 assets, before drafts, which count as extra documents. Document-level adds one translation.metadata document per entry ([plugin documentation](https://github.com/sanity-io/plugins/blob/main/plugins/%40sanity/document-internationalization/README.md)); the add-on raises Growth to 50,000 ([Sanity add-ons](https://www.sanity.io/docs/platform-management/growth-plan-add-ons)). Sources: [Contentful, Pricing](https://www.contentful.com/pricing/); [Sanity Docs, Plans and payments](https://www.sanity.io/docs/platform-management/plans-and-payments); [Sanity, @sanity/document-internationalization README](https://github.com/sanity-io/plugins/blob/main/plugins/%40sanity/document-internationalization/README.md); [Sanity Docs, Extending the Growth plan with paid add-ons](https://www.sanity.io/docs/platform-management/growth-plan-add-ons). As of 24 October 2026.

## What happens to Contentful assets, URLs and dates in the move?

Contentful assets move as files, and URLs stay put unless you change them, because your front end owned the URLs, not Contentful. The converter points each asset at its Contentful URL through `_sanityAsset` ([converter link source](https://github.com/sanity-io/contentful-to-sanity/blob/main/src/utils/contentfulLinkToSanityReference.ts), October 2026), and Sanity's importer uploads every file it references, failing the run on a missing file unless you pass `--allow-failing-assets` ([Sanity import docs](https://www.sanity.io/docs/content-lake/importing-data), October 2026). So keep the Contentful space live until the import finishes, and archive an export made with the `--download-assets` flag of Contentful's command-line interface (CLI) ([Contentful CLI docs](https://www.contentful.com/developers/docs/tutorials/cli/import-and-export/), October 2026). Slug editors become Sanity slugs ([converter source](https://github.com/sanity-io/contentful-to-sanity/blob/main/src/utils/contentfulEntryToSanityObject.ts)), so routes can stay identical.

Two traps hide in dates and history:

- **Modified dates:** the Sanity import sets `_updatedAt` to the import time on every document that holds a reference ([Sanity import docs](https://www.sanity.io/docs/content-lake/importing-data)), so keep Contentful's dates in a field of your own; [keeping search traffic through a move to Sanity](https://deploi.ca/sanity/migration/cms-to-sanity/seo-preservation) covers sitemaps and redirects.
- **History:** Contentful's version history doesn't come with the export ([Contentful CLI docs](https://www.contentful.com/developers/docs/tutorials/cli/import-and-export/)), so archive the export before cutover.

## What replaces Contentful's roles, workflows, apps and webhooks?

None of Contentful's roles, workflows, apps or webhook secrets carry over to Sanity, so you rebuild each one. The export of Contentful's command-line interface (CLI) leaves workflows, apps and webhook credentials behind ([Contentful CLI docs](https://www.contentful.com/developers/docs/tutorials/cli/import-and-export/), October 2026); [what a Contentful export leaves behind](https://deploi.ca/sanity/migration/leaving-contentful/exit-checklist) lists the rest. Here is what replaces each in Sanity, as of October 2026:

- **Roles:** Growth includes 5 roles and free viewer seats ([Sanity pricing](https://www.sanity.io/pricing)); custom roles need Enterprise ([Sanity roles docs](https://www.sanity.io/docs/user-guides/roles)). See roles and permissions.
- **Workflows:** Sanity's Workflows product is in early access ([Sanity Workflows docs](https://www.sanity.io/docs/workflows/prerelease)); Comments and Tasks come with Growth ([Sanity pricing](https://www.sanity.io/pricing)).
- **Scheduling:** Growth has Scheduled drafts for one document at a time; Content Releases needs Enterprise ([Sanity environments docs](https://www.sanity.io/docs/content-lake/environments)).
- **Apps and UI (user interface) extensions:** rebuild them as Sanity Studio plugins or custom inputs in your own React code.
- **Webhooks:** recreate them with a GROQ (Graph-Relational Object Queries) filter and a new secret ([Sanity webhooks docs](https://www.sanity.io/docs/content-lake/webhooks)).
- **Front-end queries:** rewrite Contentful Delivery and GraphQL calls in GROQ. In Deploi's judgment this is the largest line item.

## What is the step-by-step plan for a Contentful to Sanity migration?

A Contentful to Sanity migration runs as eight steps, and in Deploi's judgment the developer who owns the front end should own all of them. The plan uses Sanity's contentful-to-sanity tool, version 5.0.0 ([changelog](https://github.com/sanity-io/contentful-to-sanity/blob/main/CHANGELOG.md)).

**Moving a Contentful space to Sanity**

1. **Audit the space.** Count entries, assets and archived entries per environment, list locales, and find Rich Text tables and JSON fields.
1. **Choose localization per type.** Document-level where locales publish on different days, field-level where they ship together.
1. **Export with drafts and assets.** Include drafts, archived entries and assets ([Contentful export docs](https://www.contentful.com/developers/docs/tutorials/cli/import-and-export/)).
1. **Rewrite the generated schema.** Rewrite it as reviewed code, and declare a table schema if Rich Text used tables.
1. **Fix what the converter skipped.** Rebuild tables and JSON fields, decide what archived entries become, reshape locale fields.
1. **Validate, then import to a test dataset.** Run `sanity documents validate` on the import file ([Sanity migration docs](https://www.sanity.io/docs/content-lake/schema-and-content-migrations)), import, and compare counts per type.
1. **Rewrite queries and test routes.** Swap Contentful calls for GROQ (Graph-Relational Object Queries) queries, crawl old URLs, add redirects.
1. **Freeze and cut over.** Freeze editing, re-export, import with `--replace`, keep the imported ID list for rollback, then switch the front end.

Step 8 is how we ship large content packages with release scripts; [choosing --replace or --missing](https://deploi.ca/sanity/migration/cms-to-sanity/safe-import) covers its re-import.

## Deploi's point of view

**Where we disagree.** Two claims mislead buyers. The first is that Contentful localization is all-or-nothing per content type. Contentful's own docs describe locales enabled per field, and spaces with locale-based publishing publish one locale at a time; a team that relies on that and picks field-level localization in Sanity loses per-locale publishing. The second is the one-command migration. The official converter drops Rich Text tables, stores JSON object fields as strings, and imports archived entries as published documents.

**What we've seen.** We move content into Sanity as packages, never by hand. The first wave of deploi.ca's Shopify data section went in as one package of 406 documents and 159 images, signed off in October 2026, with check queries and a rollback by document ID list. Our decision pages go in as NDJSON with drafts-prefixed IDs, so nothing publishes before review, and with weak references, so import order doesn't matter. Our Portable Text carries a custom table block, and 229 of the 256 live answers in our Shopify FAQ hub use it, counted 24 October 2026. Those answers reach Sanity through our own Markdown to Portable Text importer; a converter that dropped tables would have stripped them from 229 of those 256 answers.

**What we'd tell you to do first.** Export the space with drafts and archived entries, then run three counts before anyone writes a schema: Rich Text fields that contain tables, JSON object fields, and archived entries. Each one is work the converter won't do for you. Then multiply entries by locales and by datasets to see which Sanity plan you are actually buying.

**What we refuse to promise.** A duration or an hours figure from a call. The drivers are the number of content types, the Rich Text features in use, the locale model, and how many front-end queries call Contentful directly; we scope from those counts.

## When this answer changes

- Contentful changes Lite's locale, content type, environment or record quotas
- Sanity changes the Growth document quota, dataset count or seat price
- contentful-to-sanity adds Rich Text table support or changes its locale output to translation.metadata documents
- Sanity Workflows leaves early access or changes plan
- Sanity moves Content Releases or dataset aliases into Growth
- Sanity changes or retires its migration skill's Contentful guide

## Ready to plan your Contentful to Sanity migration?

Contact us today to count your space the Sanity way and scope the move from those numbers. [Contact us](https://deploi.ca/contact)

## Sources

1. [Sanity, Plans that scale with you](https://www.sanity.io/pricing), checked 24 October 2026
2. [Contentful, Pricing](https://www.contentful.com/pricing/), checked 24 October 2026
3. [Sanity Docs, Plans and payments](https://www.sanity.io/docs/platform-management/plans-and-payments), checked 24 October 2026
4. [Sanity Docs, Localization](https://www.sanity.io/docs/studio/localization), checked 24 October 2026
5. [Sanity Docs, Development, staging, and production environments](https://www.sanity.io/docs/content-lake/environments), checked 24 October 2026
6. [Sanity Docs, Import data](https://www.sanity.io/docs/content-lake/importing-data), checked 24 October 2026
7. [Sanity, Contentful to Sanity plugin](https://www.sanity.io/plugins/contentful-to-sanity), checked 24 October 2026
8. [Sanity, contentful-to-sanity source: contentfulEntryToSanityObject.ts](https://github.com/sanity-io/contentful-to-sanity/blob/main/src/utils/contentfulEntryToSanityObject.ts), checked 24 October 2026
9. [Sanity, contentful-to-sanity source: command.ts](https://github.com/sanity-io/contentful-to-sanity/blob/main/src/cli/command.ts), checked 24 October 2026
10. [Sanity, @sanity/document-internationalization README](https://github.com/sanity-io/plugins/blob/main/plugins/%40sanity/document-internationalization/README.md), checked 24 October 2026
11. [Contentful, Environments](https://www.contentful.com/help/faq/environments/), checked 24 October 2026
12. [Contentful, Import and export content with the Contentful CLI](https://www.contentful.com/developers/docs/tutorials/cli/import-and-export/), checked 24 October 2026
13. [Contentful, Data model](https://www.contentful.com/developers/docs/concepts/data-model/), checked 24 October 2026
14. [Contentful, What is rich text?](https://www.contentful.com/developers/docs/concepts/rich-text/), checked 24 October 2026
15. [Sanity Docs, Block content](https://www.sanity.io/docs/studio/block-content), checked 24 October 2026
16. [Contentful, Localization with Contentful](https://www.contentful.com/developers/docs/tutorials/general/setting-locales/), checked 24 October 2026
17. [Sanity, You're stuck at 49 of 50 content types. Again.](https://www.sanity.io/contentful-vs-sanity), checked 24 October 2026
18. [Sanity, document-internationalization: Upgrade from v1](https://github.com/sanity-io/plugins/blob/main/plugins/%40sanity/document-internationalization/docs/00-upgrade-from-v1.md), checked 24 October 2026
19. [Sanity Docs, Extending the Growth plan with paid add-ons](https://www.sanity.io/docs/platform-management/growth-plan-add-ons), checked 24 October 2026
20. [Sanity Docs, How early access works (Workflows)](https://www.sanity.io/docs/workflows/prerelease), checked 24 October 2026
21. [Sanity, contentful-to-sanity source: contentfulToDataset.ts](https://github.com/sanity-io/contentful-to-sanity/blob/main/src/helpers/contentfulToDataset.ts), checked 24 October 2026
22. [Contentful, Spaces](https://www.contentful.com/help/spaces/), checked 24 October 2026
23. [Salesforce, Salesforce Signs Definitive Agreement to Acquire Contentful](https://www.salesforce.com/news/press-releases/2026/01/22/salesforce-signs-definitive-agreement-to-acquire-contentful/), checked 24 October 2026
24. [Sanity Docs, GROQ-powered webhooks](https://www.sanity.io/docs/content-lake/webhooks), checked 24 October 2026
25. [Sanity, contentful-to-sanity Changelog](https://github.com/sanity-io/contentful-to-sanity/blob/main/CHANGELOG.md), checked 24 October 2026
26. [Sanity Docs, Migrating your schema and content](https://www.sanity.io/docs/content-lake/schema-and-content-migrations), checked 24 October 2026
27. [Sanity Docs, Roles](https://www.sanity.io/docs/user-guides/roles), checked 24 October 2026
28. [Contentful, Locale-based publishing](https://contentful.com/help/localization/locale-based-publishing), checked 24 October 2026
29. [Sanity, contentful-to-sanity source: contentfulLinkToSanityReference.ts](https://github.com/sanity-io/contentful-to-sanity/blob/main/src/utils/contentfulLinkToSanityReference.ts), checked 24 October 2026
30. [Sanity Docs, Configure the Portable Text Editor](https://www.sanity.io/docs/studio/portable-text-editor-configuration), checked 24 October 2026
31. [Sanity Blog, What's new in August](https://www.sanity.io/blog/august-releases-2026), checked 24 October 2026
32. [Sanity, contentful-to-sanity source: createIntlFields.ts](https://github.com/sanity-io/contentful-to-sanity/blob/main/src/utils/createIntlFields.ts), checked 24 October 2026
33. [Sanity on GitHub, sanity-migration skill](https://raw.githubusercontent.com/sanity-io/agent-toolkit/main/skills/sanity-migration/SKILL.md), checked 25 October 2026
