Friday, January 17, 2025
How to Perform a Sanity CMS Migration: Step-by-Step Guide

Sanity CMS migrations require a code-first approach centered on custom scripting rather than automated tools. Unlike traditional CMS platforms, Sanity provides no one-click migration wizard. Instead, it offers CLI-based and API-driven methodologies that demand technical expertise but deliver complete control over content transformation.
This technical foundation makes Sanity a natural fit for composable architecture implementations, where headless CMS capabilities enable marketing teams to manage content independently while development teams maintain control over performance and integrations. This guide walks through the technical steps website managers and technology leaders need to execute a successful Sanity migration without disrupting business operations.
Why Sanity Migrations Are Different
Most CMS migrations fail before technical work begins because teams underestimate organizational planning, treating migrations as simple technical lifts rather than multi-stakeholder projects requiring cross-functional coordination. Failures stem from inadequate organizational planning, underestimated content modeling complexity and insufficient allocation of resources to change management.
Sanity's architecture creates unique requirements:
- Schema changes do not automatically alter existing content; all migrations must be intentional and explicitly scripted
- The platform enforces a maximum of 25 requests per second API rate limit, with the recommended implementation pattern processing 50-100 documents per transaction
- HTML content from legacy platforms must be converted to Portable Text JSON format during migration
These constraints mean your migration timeline depends heavily on content complexity, schema design decisions and integration requirements. Budget 30-40% of total project time for organizational planning and change management before writing any migration code.
Step 1: Complete Pre-Migration Planning
Sanity's architecture requires defining document types, fields and relationships in JavaScript or TypeScript before migration begins. The official documentation emphasizes schema-first technical discovery as the foundation of every successful migration.
Pre-migration checklist:
- Audit existing content structure in your current CMS
- Map all fields to Sanity equivalents using platform-specific field type mappings (strings, references, Portable Text blocks for rich content)
- Document cross-content relationships, dependencies and reference structures
- Identify custom plugins, extensions or schema-as-code requirements needed for your B2B content patterns
- Create comprehensive URL redirect mapping to preserve SEO value
Critical step: Export your existing dataset for backup using sanity dataset export. This creates your rollback capability if issues arise during migration.
Step 2: Design Your Content Schema
Sanity uses a code-first schema approach where content models are defined as JavaScript or TypeScript objects. This differs from WordPress's GUI-based schema builders, allowing for more flexible and version-controlled content architecture.
Basic schema structure:
export default {
name: 'article',
type: 'document',
title: 'Article',
fields: [
{
name: 'title',
type: 'string',
validation: Rule => Rule.required().min(10).max(80)
},
{
name: 'slug',
type: 'slug',
options: { source: 'title', maxLength: 96 }
},
{
name: 'body',
type: 'array',
of: [{ type: 'block' }]
}
]
}
For B2B SaaS websites, design schemas for:
- Case studies with client references and results metrics using documented reference-based schema with key metrics objects
- Modular landing pages using page builder patterns with reusable component types (hero, features, testimonials, ctaBlock, pricingTable, faqSection)
- Reusable SEO objects across all content types with standardized fields for metaTitle, metaDescription, ogImage and noIndex controls
- Product documentation with version control through Sanity's schema migration commands and document versioning capabilities
Deploy schemas to your Sanity project via the CLI and validate thoroughly in development environments first, then test in staging before production deployment. Sanity recommends validating schema changes in a development environment before applying to production datasets to prevent backward-incompatible changes that corrupt existing content. This three-phase validation approach ensures schema integrity throughout migration.
Step 3: Extract and Transform Content
Content extraction methods vary significantly by source platform. The technical approach centers on three core steps:
- API-based extraction from source systems (WordPress REST API, Contentful APIs, etc.)
- Custom transformation scripts that convert platform-specific formats into Sanity's document model, including HTML-to-Portable Text conversion for rich content
- Batch import to Sanity using NDJSON format with the Sanity CLI or programmatic client libraries
Per Sanity's migration documentation, WordPress migrations use the WordPress REST API to retrieve posts, pages, categories and media. Contentful migrations leverage Sanity's official contentful-to-sanity plugin or the Contentful APIs directly.
WordPress to Sanity Migration Workflow
Sanity's WordPress course outlines a five-step process using the WordPress REST API:
import {htmlToBlocks} from '@sanity/block-tools'
import {JSDOM} from 'jsdom'
// Fetch from WordPress REST API
const response = await fetch('https://yoursite.com/wp-json/wp/v2/posts');
const wpPosts = await response.json();
// Transform to Sanity documents with proper schema mapping
const sanityDocs = wpPosts.map(post => ({
_type: 'article',
_id: `wp-${post.id}`,
title: post.title.rendered,
slug: {
_type: 'slug',
current: post.slug
},
body: htmlToBlocks(post.content.rendered, schema, {
parseHtml: html => new JSDOM(html).window.document
}),
publishedAt: post.date,
author: {
_type: 'reference',
_ref: `author-${post.author}`
}
}));
// Import to Sanity using transactions for batch processing
const transaction = client.transaction();
sanityDocs.forEach(doc => transaction.createOrReplace(doc));
await transaction.commit();The critical transformation: WordPress stores content as HTML. Sanity uses Portable Text, a structured JSON format. Use the @sanity/block-tools library's htmlToBlocks function to convert HTML to Portable Text blocks.
HTML conversion complexity requires careful planning. Teams must implement htmlToBlocks() conversion functions with custom parsing rules for platform-specific HTML structures:
- Custom shortcodes require parser development using tools like
@sanity/block-toolsand JSDOM - Embedded media players need dedicated handling rules
- Non-standard markup patterns must be audited before writing transformation scripts
Audit your content for these edge cases before beginning development work.
Contentful Migration
Sanity provides the contentful-to-sanity plugin that automates most conversion work for Contentful migrations:
npx contentful-to-sanity \
-s <space-id> \
-t <management-token> \
-a <access-token> \
./migrateThis plugin automatically maps content types, converts rich text to Portable Text, translates references and downloads media assets.
Media Asset Migration
Sanity's media migration documentation outlines a comprehensive five-step process:
- Export datasets containing assets using
sanity dataset export - Upload assets via the Media Library HTTP API
- Link assets to target datasets through API calls
- Update document references to point to new asset locations
- Optionally migrate asset metadata including tags and descriptions
Creating mapping documents linking old asset IDs to new Sanity asset references is critical, as it preserves content relationships during the transition and enables reference updating across all documents.
Step 4: Execute the Migration
Migration execution requires respecting API constraints and building fault-tolerant scripts. Sanity enforces a maximum of 25 requests per second for API operations. The recommended implementation pattern, documented in batch processing guidance, processes 10 documents per transaction with throttling:
const transaction = client.transaction()
documents.forEach(doc => transaction.createOrReplace(doc))
await throttle(() => transaction.commit())
Scripts without throttling fail mid-process. Implement batch processing and rate limiting using throttling libraries like p-throttle before running production migrations.
Use idempotent methods for safe re-execution:
createOrReplace()for updates that can safely run multiple times without duplication or data corruptioncreateIfNotExists()for new documents that should not create duplicates on script re-execution
These idempotent methods are critical for production migrations where re-runs are inevitable due to failures, testing or rollbacks. Scripts without idempotency guarantees are a common cause of data corruption when failures require restarts. Always use createOrReplace() or createIfNotExists() methods instead of create() to ensure safe re-execution, and combine these methods with transactional mutations to maintain data integrity.
Generate NDJSON files for bulk import, then use CLI commands like sanity dataset import <file> with options including --replace to replace existing documents, --skip to skip documents that already exist or --missing to import only documents not present in the target dataset.
sanity dataset import output.ndjson production --replace --allow-failing-assetsThe --allow-failing-assets flag lets imports continue despite missing media files. This prevents entire migrations from failing when assets referenced in content are unavailable or have been removed from the source system.
With migration scripts executing successfully, validation becomes the priority to ensure content integrity before production deployment.

Step 5: Validate and Test
Multi-stage validation catches issues before they reach production. Run validation systematically across three environments: development, staging and production.
Schema validation commands:
sanity documents validate
sanity schema validate
The sanity documents validate command validates existing documents against your current schema definition, while sanity schema validate validates schema definitions before applying migrations. Execute these validation steps in development environments before production deployment.
Critical warning: Teams that skip staging environment testing discover content inconsistencies after production launch. Comprehensive validation across development, staging and production environments is required. Always test in staging first.
Content integrity validation involves multiple checkpoints:
- Verify all image URLs resolve and assets migrated successfully
- Test cross-document references maintain links and relationships
- Validate Portable Text renders properly and HTML conversion completed correctly
- Run diff checks comparing content structure between source and migrated content
- Verify UTF-8 encoding and special characters render correctly
SEO and integration validation requires additional verification:
- Test all 301 redirects function correctly
- Verify meta titles, descriptions and Open Graph tags migrated accurately
- Submit updated XML sitemaps to search consoles
- Confirm webhooks fire and third-party integrations work properly
- Measure Core Web Vitals against pre-migration baselines using Lighthouse audits
Target these performance benchmarks: TTFB under 200ms, LCP under 2.5 seconds and GROQ queries averaging under 100ms. These metrics are critical success indicators for ensuring content delivery performance meets user experience standards.
Validation completion signals readiness for post-migration operational tasks that ensure long-term success.
Step 6: Complete Post-Migration Tasks
Technical validation continues after go-live. Run sanity documents validate to identify validation errors across all migrated content. Update downstream queries in your frontend application to align with new schema structures.
Team training requirements:
Sanity's Learn platform specifies training must address distinct team needs:
- Content Teams: New editorial workflows, Sanity Studio navigation, visual editing features, reference management and collaboration
- Development Teams: Schema-as-code management, Studio customization, GROQ/GraphQL integration, RBAC configuration and security practices
Structure training with initial onboarding using official Sanity Learn courses, role-specific workshops and documented internal processes. Per Webstacks' analysis, proper Sanity implementation enables marketing team autonomy for content updates, campaign launches and landing page creation without developer dependencies, but only when teams receive adequate training on Sanity Studio's content management capabilities.
Monitoring setup:
- Configure API performance tracking with event-driven alerting for validation errors
- Set up content integrity checks verifying asset migration, document references and relationship validity
- Monitor analytics for traffic disruptions and SEO preservation during transition
- Track publishing velocity and content workflow efficiency
- Implement systematic review cadences (daily for errors, weekly for trends, monthly for capacity)
Moving Forward with Your Migration
Your migration decisions today shape whether content operations scale smoothly or create new bottlenecks as your company grows. Schema design determines marketing team autonomy. Script architecture determines migration reliability. Training investment determines adoption success. Because your website is never done, the infrastructure you build during migration must support continuous optimization rather than just launch-day requirements.
For B2B SaaS companies managing complex content models, integrations with marketing automation platforms and enterprise compliance requirements, the migration complexity often exceeds internal team capacity. Schema design decisions made during migration determine whether your marketing team gains content independence or remains dependent on developer queues for routine updates.
Talk to Webstacks about implementing composable architecture that gives your marketing team independence while maintaining performance benchmarks and enabling zero-downtime migrations throughout your Sanity implementation.



