Generated banner for Sanity Migration
Generated logo for Sanity Migration

Sanity Migration

SanityOfficialPublished by Sanity

  • Skill
  • Tool integration
  • Software development
  • MIT
  • No issues found

From the author

Plans, implements, and reviews migrations from other CMSes and content systems into Sanity. Use when migrating or replatforming to Sanity from AEM, Adobe Experience Manager, Contentful, Strapi, Webflow, WordPress, Payload, Drupal, Markdown/MDX/frontmatter files, WXR/XML exports, CMS APIs, database dumps, static HTML, or when designing extraction, transformation, Portable Text conversion, asset migration, redirects, validation, and cutover workflows.
— the description by Sanity

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

  1. Download the skill as a ZIP:

    https://autogineer.com/agent-skills/sanity-io/sanity-migration/download
  2. Unzip 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

  1. Read references/general.md first.

  2. If the source platform is known, also read its guide:

    • AEM / Adobe Experience Manager: references/aem.md

    • Contentful: references/contentful.md

    • Strapi: references/strapi.md

    • Webflow: references/webflow.md

    • WordPress / WXR / Elementor: references/wordpress.md

    • Payload: references/payload.md

    • Drupal: references/drupal.md

    • Markdown / MDX / frontmatter files: references/markdown.md

  3. Before writing code, produce a short migration plan covering source access, content scope, schema decisions, extraction, transformation, import, validation, redirects, and cutover.

  4. 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, or sanity datasets import --replace so 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, and defineArrayMember if 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-practices

Stop 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

references/aem.md

AEM to Sanity

What to Determine First

Adobe Experience Manager projects vary widely. Before writing migration code, determine:

  • AEM 6.5 on-premise or AEM as a Cloud Service.

  • Author-tier access, publish-tier access, or exported content only.

  • Whether content is mostly pages with components, Content Fragments, Experience Fragments, DAM assets, or a mixture.

  • Whether the site uses Core Components, custom components, or both.

  • Whether Multi-Site Manager language copies are in scope.

  • Whether unpublished drafts, inherited content, and Experience Fragments must be preserved.

Authentication

  • AEM 6.5/on-premise commonly supports HTTP Basic auth with a read-only service account.

  • AEM as a Cloud Service production does not use Basic auth; use Adobe IMS/service credentials or another approved bearer-token flow.

  • Publish tier exposes published content only. Use author-tier access when drafts, unpublished content, or inherited authoring state is in scope.

Extraction Paths

Use the most structured source that covers the required scope:

  • Content Fragments: use AEM GraphQL. Discover types from /content/_cq_graphql/global/endpoint.GQLschema, then query fragments through /content/_cq_graphql/global/endpoint.json.

  • Core Component pages: use .model.json where Sling Model exporters are present.

  • Custom component pages: use .infinity.json or .tidy.infinity.json to inspect raw JCR nodes under jcr:content.

  • Bulk discovery: use QueryBuilder to enumerate pages, fragments, DAM assets, tags, and Experience Fragments.

  • DAM assets: fetch binaries from /content/dam/... and metadata from /content/dam/.../jcr:content/metadata.json.

  • Dialog/schema discovery: if repository or component paths are available, inspect _cq_dialog.infinity.json and sling:resourceSuperType chains to infer component fields.

Save raw extraction responses to disk before transforming. AEM APIs can be slow, auth-sensitive, and environment-specific.

aem-to-sanity Toolkit Pattern

For large AEM migrations, use or mirror the staged aem-to-sanity toolkit pattern from github.com/demo-repositories/aem-to-sanity.

Pipeline stages:

  • Schemas (migrate:schema): fetch _cq_dialog.infinity.json, walk Granite UI dialogs and sling:resourceSuperType chains, discover slots/container drop zones, and emit Sanity object/page builder schemas.

  • Types (typegen): generate sanity.types.ts from emitted schemas.

  • Extract (aem-extract): walk content roots through .infinity.json, following depth truncation markers, and write raw files under an AEM cache directory.

  • Tags (aem-tags): emit taxonomy/category documents from /content/cq:tags/... when AEM tags are in scope.

  • Transform (aem-transform): map sling:resourceType through the generated registry, coerce string booleans/numbers, convert HTML to Portable Text, and resolve tag refs.

  • Assets (aem-assets): dedupe, download from AEM, upload to Sanity Media Library or assets, link into the dataset, and rewrite clean documents.

  • Import (aem-import): commit documents with transaction().createOrReplace(), importing categories before pages.

Operational defaults from the toolkit:

  • Dry-run by default; real writes require MIGRATION_DRY_RUN=false.

  • Per-tenant folders hold credentials, component paths, content roots, tag roots, component exceptions, generated caches, and reports.

  • Run a doctor step before migration to catch missing env/config drift.

  • Use content-derived identity: JCR path -> _id, JCR UUID -> _key, DAM path -> asset manifest key.

  • Treat unknown component shapes as findings in reports, not immediate fatal errors, unless config or schema validation is broken.

Mapping to Sanity

Map AEM shapes by editorial meaning, not JCR structure:

  • cq:Page with authored components can become a page document with a page builder array.

  • Content Fragments usually become standalone document types.

  • Reusable Content Fragments, Experience Fragments, tags, people, products, or snippets should become referenceable documents when reused.

  • AEM text/RTE components become Portable Text fields or custom Portable Text objects.

  • AEM image components become Sanity image fields with migrated asset references.

  • AEM tags become taxonomy documents before content documents are written.

  • MSM language copies can map to document-level localization with language fields and translation metadata documents.

Use sling:resourceType as the main discriminator for component-to-object mapping.

Transformation Notes

  • Strip JCR/system fields such as jcr:primaryType, jcr:created, and sling:resourceType unless they are needed in migration metadata.

  • Convert RTE HTML to Portable Text with source-specific preprocessing for empty paragraphs,   spacer rows, inline styles, spans, tables, and double-encoded entities.

  • Normalize paths and slugs. AEM URLs often include /content/<site>/<locale>/... prefixes and .html extensions.

  • Deduplicate DAM assets by full DAM path, asset UUID, or source URL before upload.

  • Use deterministic IDs based on AEM paths or UUIDs.

  • Create translations and parent/child references after all target documents exist.

Load Order

  1. Taxonomies/tags from /content/cq:tags.

  2. DAM assets or asset manifest.

  3. Content Fragments and reusable Experience Fragments.

  4. Page/content documents.

  5. Translation metadata and post-import relationship fixes.

Gotchas

  • .model.json can silently omit custom components without Sling Model exporters. Cross-check representative pages against .infinity.json.

  • .infinity.json may be depth-limited or truncated on large trees. Detect truncation and recurse into child paths if needed.

  • Publish-tier APIs expose published content only. Use author-tier access when drafts or unpublished changes are in scope.

  • DAM URLs may require auth or point at internal hostnames. Verify asset fetchability before a large import.

  • AEM tags are namespaced paths, not flat slugs.

  • MSM inheritance can produce locale pages with inherited source-language fields. Detect identical translated fields before assuming content is localized.

  • Experience Fragments live in a separate content tree and must be migrated before pages that reference them.

  • Source-edited RTE content can contain layout tables, scripts, or arbitrary HTML that needs manual cleanup.

Validation Checklist

  • Compare page, fragment, tag, Experience Fragment, and DAM counts against source queries.

  • For each major template, verify every sling:resourceType has an explicit Sanity mapping or an intentional skip.

  • Spot-check .model.json and .infinity.json parity for custom components.

  • Confirm language variants have correct slugs, language fields, and translation metadata.

  • Confirm all DAM references resolve to Sanity assets or Media Library assets.

  • Crawl old AEM URLs and verify redirects to the new frontend.

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