Sanity Migration
SanityOfficialPublished by Sanity
- Skill
- Tool integration
- Software development
- MIT
- No issues found
AutoGineer summary
Written by AutoGineer from the skill’s own files, not by the author
This skill provides a systematic approach to migrating content from various CMS platforms into Sanity. It treats migration as an ETL (Extract, Transform, Load) project, emphasizing deterministic scripts, content modeling, and validation over manual operations. The skill includes specific guidance for platforms such as AEM, Contentful, Strapi, Webflow, WordPress, Payload, Drupal, and Markdown-based systems, ensuring that content is properly mapped, transformed into Portable Text, and validated before final cutover.
What it does
- Provides a structured workflow for planning and executing CMS-to-Sanity migrations.
- Offers platform-specific guidance for extracting data from common CMS environments.
- Defines best practices for mapping source content to Sanity schemas and Portable Text.
- Requires the creation of migration plans, content inventories, and validation reports.
- Encourages the use of deterministic scripts for repeatable and reliable data imports.
- Includes procedures for handling assets, redirects, and final cutover synchronization.
When to use it
- When replatforming a website or application to use Sanity as the content backend.
- When moving content from legacy systems like AEM, Drupal, or WordPress.
- When migrating static files like Markdown or MDX into a structured CMS.
- When you need to perform a complex data transformation and cleanup during an import.
- When you need to ensure data integrity through validation checks and delta syncs.
Advantages
- Reduces risk by mandating planning and validation steps before execution.
- Promotes repeatable migrations through script-based ETL patterns.
- Ensures content is modeled for Sanity's capabilities rather than just copied.
- Provides clear paths for handling complex data like rich text and assets.
- Supports iterative development through deterministic ID management.
Usage examples
- “I need to migrate my site from Contentful to Sanity. Where do I start?”
- The agent will guide you through the Contentful-specific extraction process, help you plan your content mapping, and suggest using the contentful-to-sanity toolkit for an initial pass.
- “How should I handle AEM content fragments during a migration?”
- The agent will provide instructions on using AEM GraphQL to extract fragments and mapping them to Sanity document types or page builder blocks.
- “Create a migration plan for my WordPress site.”
- The agent will outline the steps to export WXR data, map WordPress posts to Sanity schemas, convert HTML to Portable Text, and set up redirects.
Install
Download the skill as a ZIP:
https://autogineer.com/agent-skills/sanity-io/sanity-migration/downloadUnzip it into the cross-client skills folder of your project:
mkdir -p .agents/skills && unzip sanity-migration.zip -d .agents/skills
Documentation by Sanity
Sanity Migration
Use this skill for CMS-to-Sanity migration work. Treat migration as a content strategy and ETL project, not a blind lift-and-shift.
Required Workflow
Read
references/general.mdfirst.If the source platform is known, also read its guide:
AEM / Adobe Experience Manager:
references/aem.mdContentful:
references/contentful.mdStrapi:
references/strapi.mdWebflow:
references/webflow.mdWordPress / WXR / Elementor:
references/wordpress.mdPayload:
references/payload.mdDrupal:
references/drupal.mdMarkdown / MDX / frontmatter files:
references/markdown.md
Before writing code, produce a short migration plan covering source access, content scope, schema decisions, extraction, transformation, import, validation, redirects, and cutover.
Prefer deterministic, repeatable scripts for real migrations. Write and review migration scripts, mappings, and validation checks; do not rely on one-off content operations for large content volumes.
Deliverables to Produce
For implementation or planning tasks, produce these artifacts or explain why they are not needed:
Content inventory: source types, counts, locales, status/draft scope, assets, and relationship types.
Source-to-Sanity mapping: document types, object types, references, Portable Text fields, asset fields, IDs, and skipped content.
Extraction approach: credentials/access needed, API/export commands, raw snapshot location, and known blind spots.
Transform/import plan: deterministic IDs, write order, asset handling, rich text conversion, validation, and rerun strategy.
Cutover plan: delta sync/content freeze, redirects, broken-link checks, SEO metadata, and manual cleanup.
Defaults
Use stable document IDs derived from source IDs, slugs, paths, or hashes.
Use
createOrReplace,createIfNotExists, orsanity datasets import --replaceso reruns converge.Snapshot extracted source data to disk before transforming it.
Import or create referenced documents before documents that reference them.
Convert rich text to Portable Text instead of storing raw HTML or Markdown strings.
Upload assets to Sanity or the Media Library; do not leave production content dependent on legacy CDN URLs.
Track per-document quality issues and produce a validation summary before cutover.
Preserve legacy URLs and source IDs for redirects, QA, and future debugging.
Sanity Guardrails
Model what content is, not how the old site rendered it.
Use documents for reusable or independently managed entities; use objects for content owned by one document.
Use
defineType,defineField, anddefineArrayMemberif authoring Sanity schemas.Use image/file fields with uploaded Sanity assets or Media Library assets, not legacy CDN URLs.
Use Portable Text arrays for rich text and custom blocks; do not store raw HTML as the canonical body.
Run schema extraction and TypeGen after schema or GROQ query changes when the project uses TypeScript.
Deploy or apply schema changes before using MCP/content tools against the target dataset.
For deeper Sanity implementation guidance, use sanity-best-practices if it is already available. If it is not installed, tell the user they can add it with:
npx skills add sanity-io/agent-toolkit --skill sanity-best-practicesStop and Ask
Stop before coding when any of these are unclear:
Source access path, credentials, export file, or database connection.
Target Sanity project/dataset or whether a scratch dataset should be used.
Draft, archived, scheduled, locale, or version history scope.
Whether media files should be migrated and whether asset URLs/files are accessible.
Whether the destination schema exists or should be designed as part of the migration.
Do Not Do This
Do not create random IDs for source-backed documents.
Do not fetch-then-create referenced documents; use deterministic IDs and
createIfNotExists/createOrReplace.Do not run bulk migrations through MCP content tools when NDJSON or scripts are appropriate.
Do not flatten locale fallback values into translations unless requested.
Do not leave TODOs for required media, authors, references, or rich text conversion.
Do not declare a migration done without count checks, sample checks, reference checks, and route/redirect checks.
Reference Map
Use references/general.md for shared migration principles and the platform references for source-specific extraction routes, modeling traps, and validation checks.
For source systems not explicitly covered, apply references/general.md and adapt the closest platform pattern:
API-first CMSes: start from Contentful, Strapi, or Payload.
Monolithic/page-builder systems: start from WordPress, Drupal, Webflow, or AEM.
HTML-heavy exports: start from the WordPress and Webflow rich-text guidance.
Markdown-first sources: start from
references/markdown.md.
Files
- ATTRIBUTION.mdAdded by AutoGineer863 B
- LICENSELicence file added by AutoGineer1.0 KiB
- SKILL.md5.3 KiB
- references/aem.md6.8 KiB
- references/contentful.md9.5 KiB
- references/drupal.md4.4 KiB
- references/general.md12.6 KiB
- references/markdown.md5.1 KiB
- references/payload.md7.5 KiB
- references/strapi.md6.3 KiB
- references/webflow.md5.7 KiB
- references/wordpress.md12.5 KiB
references/contentful.md
Contentful to Sanity
What to Determine First
Before writing migration code, determine:
Space ID, environment, locales, and whether multiple environments must be reconciled.
Access level: Content Delivery API, Content Preview API, Content Management API, CLI export, or export file.
Whether drafts, archived entries, unpublished entries, and deleted entries are in scope.
Whether the migration should use the
contentful-to-sanitypackage for a first pass or a custom transform for remodeling.Rich text field formats, embedded entries/assets, and any custom app fields.
Which content types should become Sanity documents, objects, page builder blocks, references, or be retired.
Extraction Paths
Common options:
Contentful CLI export: best for a complete file-based snapshot of content types, entries, assets, locales, and editor interface metadata.
Content Management API: best when drafts, unpublished content, archived entries, or environment-specific migration logic are needed.
Content Delivery API: good for published-only migrations and frontend parity work.
Content Preview API: useful when draft or preview state matters but full management access is not available.
contentful-to-sanity: Sanity-maintained tooling that can create a Sanity project/schema and prepare adataset.ndjsonfrom a Contentful space. Use it for quick lift-and-shift or as an exploration tool, then review the generated schema before committing to it.
Snapshot exports before transformation so field mappings can be iterated offline.
If using the official Contentful CLI directly:
npx contentful-cli login
npx contentful-cli space export --space-id <space-id> --export-dir ./contentful-exportThe export JSON should contain contentTypes, entries, assets, and locales. Analyze those before designing the transform. If credentials are already configured locally, a management token may exist in ~/.contentfulrc.json, but do not assume it is present or safe to use without user confirmation.
Using contentful-to-sanity
Use contentful-to-sanity when the project needs a fast first-pass lift-and-shift, schema exploration, or a generated dataset.ndjson to inspect. Do not treat its generated schema as final without content modeling review.
Inputs to collect:
Contentful space ID.
Contentful Content Delivery API access token.
Contentful Content Management API token.
Destination Sanity project and dataset, usually a clean Studio or scratch dataset for review.
Typical workflow:
npm create sanity@latest -- --template clean --create-project "Migrated Contentful" --dataset production --output-path ./migrate
npx contentful-to-sanity@latest -s <space-id> -t <management-token> -a <delivery-token> ./migrate
cd ./migrate
npx sanity datasets import ./dataset.ndjson productionIf the generated Studio imports schemas from ./schemas, update it to use the generated schema export from ./schema as instructed by the package output.
Review before using the output as production architecture:
Generated document and field names.
Contentful content types that should be consolidated, split, or remodeled.
Reference fields and embedded entry handling.
Rich Text conversion quality, especially embedded entries and assets.
Locale behavior and fallback values.
Asset metadata and missing alt text.
Whether IDs are deterministic enough for reruns and future deltas.
Use custom extraction/transform code instead when:
Drafts, archived entries, unpublished entries, or deleted entries are in scope.
The target Sanity model intentionally differs from the Contentful model.
Rich Text embedded entries need custom Portable Text or page builder objects.
Locales need a document-level localization model rather than the generated default.
The migration must run repeatedly for delta sync before cutover.
You need detailed quality reports, custom validation, or source-specific cleanup.
Content States and Locales
Contentful state needs explicit mapping:
Draft:
fieldStatusisdraft,publishedCounteris0, and no published version exists. Import only a Sanity draft document:drafts.<documentId>.Published:
fieldStatusispublished; current data matches the live version. Import only the published Sanity document:<documentId>.Changed: the entry was published, then edited. Import two documents:
drafts.<documentId>from the export/current draft data, and<documentId>from the Content Delivery API's last published data.
When the Contentful export contains more than one locale, use document-level localization unless the project explicitly uses a field-level model:
Determine the base locale from the export, not from assumptions.
Use the source
sys.idfor the base document ID.Use
<sys.id>__i18n_<locale>for translation document IDs.Use
translation.<sys.id>for translation metadata.Create translation documents only when that locale has actual field values.
Omit missing localized fields instead of copying fallback values into translation documents.
Apply the draft/published/changed logic to every locale variant.
Convert Contentful Rich Text separately per locale.
Mapping to Sanity
Map Contentful concepts deliberately:
Symbolmaps tostring.Textmaps totext.RichTextmaps to Portable Text.IntegerandNumbermap tonumber.Datemaps todatetime.Mediamaps toimageorfile.Linkto Entry maps toreference.Arrays map to Sanity arrays, with array members chosen from the field's item type.
Content types usually become Sanity document types when independently managed or queried.
Contentful fields that are only meaningful inside one parent become Sanity object fields or named object types.
Single-reference and multi-reference fields become Sanity references.
Contentful assets become Sanity image/file assets with asset field metadata such as title, description, alt text, and source URL where useful.
Contentful locales can map to field-level localization or document-level localization depending on the target editorial workflow.
Contentful Rich Text should become Portable Text, preserving marks, embedded entries, embedded assets, hyperlinks, and custom blocks as supported by the target schema.
Use the migration to reduce over-generic content types and remove fields that exist only because of Contentful app or layout constraints.
If a Contentful field is an array of strings but behaves like a taxonomy, promote it to reference documents instead of preserving it as strings. Good candidates include product tags, article tags, topics, industries, audiences, and filters used by navigation/search. Create the taxonomy documents first, then reference them from migrated entries.
Transformation Notes
Preserve original Contentful entry IDs in deterministic Sanity IDs or migration metadata.
Build ID maps for every entry and asset before transforming references.
Convert Rich Text JSON structurally instead of rendering to HTML first when possible. Use
@portabletext/contentful-rich-text-to-portable-textwhen it fits the target schema, then add custom handling for embedded entries/assets.Handle embedded entries with explicit mapping decisions: inline object, reference block, page builder object, or skipped unsupported block.
Preserve locale fallbacks intentionally. Do not flatten fallback values into translated documents without recording that they were inherited.
Import reusable taxonomies, people, and shared modules before documents that reference them.
Gotchas
Published-only APIs omit draft and unpublished content.
Contentful locale fallbacks can hide missing translations. Decide whether to preserve missingness or fill with fallback content.
Rich Text embedded entries often carry presentation-specific modules. They need custom Portable Text or page builder object mappings.
Asset fields may store title/description but not enough accessibility metadata. Flag missing alt text for editorial review.
Contentful asset exports can be incomplete or corrupt. Check downloaded asset files for zero-byte size, missing files, unexpected content type, and failed URLs before building
_sanityAssetreferences.Some generated schemas from automated tools are a starting point, not a final content model.
Contentful field validations and required flags do not guarantee every historical entry is clean.
If only code is available, inspect
contentfulClient.getEntries({content_type: ...}), GraphQL queries, Contentful TypeScript interfaces, component props, andcontentful/migrations/files to reconstruct the content model.
Validation Checklist
Compare content type, entry, asset, and locale counts with the source export.
Confirm every Contentful content type is mapped, skipped, or intentionally consolidated.
Confirm all reference fields resolve to existing Sanity document IDs.
Spot-check Rich Text entries with embedded assets, embedded entries, tables, lists, and links.
Verify promoted string taxonomies have one canonical document per unique value and all source entries reference those documents.
Verify every exported asset path exists and has a non-zero file size before import.
Verify locale fallback behavior with real translated and untranslated entries.
Verify draft, published, and changed entries produce the expected Sanity draft/published documents.
Verify translation metadata documents link all language variants for each entry.
Confirm frontend GROQ queries return shapes equivalent to the old Contentful queries or the agreed new contract.
Requirements and compatibility
Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta
“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.
Needs: Needs Node.js
Security
No issues found by our static scan· No issues found
A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.
Attribution and licence
- Published by
- Sanity
- Publisher
- Sanity (Official)
- Source
- sanity-io/agent-toolkit · skills/sanity-migration · commit 3ed3a14
- Licence
- MIT License (redistribution allowed)
- LICENSE (added by AutoGineer from LICENSE)
- ATTRIBUTION.md (written by AutoGineer)
- Synced
AutoGineer is not affiliated with or endorsed by Sanity or Sanity.
Download ZIP
The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download sanity-migration.zip