Tips for migrating from WordPress to Sanity, including using WPGraphQL and block tools.

28 replies
Last updated: Mar 10, 2021
anyone have a successful migration from wordpress to sanity? willing to share your process?
AI Update

Yes! Migrating from WordPress to Sanity is definitely doable, and there's actually a full course on this in the Sanity documentation. Here's what a typical process looks like:

General Migration Approach

The key thing to understand is that migration isn't just about moving data—it's an opportunity to restructure your content for the better. You can finally escape WordPress's "presentation lock-in" and create more reusable, structured content.

The Step-by-Step Process

1. Prepare Your Sanity Schema

Start by creating your schema types in Sanity Studio. This gives you immediate visual feedback as you migrate and lets you collaborate with your content team on the new editorial experience. You can restructure things here—for example, converting WordPress pages with different templates into more appropriate document types (staff profiles → person documents, office locations → location documents).

2. Use the Sanity CLI Migration Tool

The recommended approach is using Sanity's CLI:

npx sanity@latest migration create

This gives you built-in abstractions, automatic batching to avoid rate limits, dry-run mode by default, and document validation against your schema.

3. Start Simple and Build Incrementally

Don't try to migrate everything perfectly in one go. Start with just _id and _type fields, then add slugs, titles, and other fields in subsequent runs. This incremental approach with real-time Studio feedback creates an effective development workflow.

4. Convert HTML to Portable Text

This is where @sanity/block-tools comes in. Install it with:

npm install -D @portabletext/block-tools jsdom

The htmlToBlocks function handles basic formatting automatically, but you can define custom deserialization rules for complex HTML structures—like extracting data from <figure> or <img> tags and transforming them into custom block types.

5. Handle Assets Performantly

Uploading images requires special attention:

  • Don't use sequential loops (way too slow)
  • Implement concurrent uploads with rate limiting using tools like p-limit
  • Fetch assets from URLs and upload using Sanity Client
  • Attach the returned asset document IDs as references in your documents

6. Make Your Scripts Idempotent

Your migration scripts should be idempotent—meaning you can run them multiple times with the same result. Use deterministic IDs so scripts can skip or intentionally rewrite documents. This is crucial because you'll likely run migrations multiple times throughout the project.

7. Handle Errors Gracefully

Legacy WordPress content is often messy—missing images, corrupted content, broken references. Every retrieval must handle cases where content is corrupted or references missing elements.

Key Resources

The full WordPress to Sanity migration course walks through the entire process with practical examples. There's also a comprehensive guide on general migration principles that applies to any content migration.

Pro Tips

  • Use TypeScript types generated from your schemas for type-safe transformations
  • Run migrations in dry-run mode first before executing against production
  • Complex page builder outputs (Elementor, Divi) can be challenging—sometimes it's better to start fresh with those
  • Preserve important metadata like creation dates, authors, and taxonomies during migration

The migration is definitely worth it—you'll end up with cleaner, more queryable content that's not locked into any particular presentation format.

i think there were some other guide on that posted here (though the history doesn’t go back far enough) but our site has a lot of ACF and Woo so we’ve been using WPGraphQL for migrations. It’s not perfect though. in particular, you can’t pull drafts or private posts from WPGraphQL
are you saying you didn’t migrate the content? you just also request it alongside sanity content?
oh i used WPGraphQL to pull content and write it in to Sanity
ahhh
interesting
this primarily because im not a WordPress dev so maybe this convoluted lol
haha
so then you did mutations in sanity to create/save imported pages?
but it’s definitely not a 1-to-1 transform and we’re still in the middle of auditing our pages
by hand
got it
but at least this gets the content partially on there
yeah, the use case i have right now is only a small blog with about ~100 posts
so not too terrible
if it’s only blog posts, then i think the wordpress REST API would be helpful too
along the same path? just query into sanity to create mutation?
yeah for your use case, i would go with the rest API because i hate plugins lol
haha… same!
other than ACF
ACF is the Sanity of WordPress
agree!
do you have any code samples you could share of your mutations? I honestly haven’t worked with them yet
i don’t atm but it would go something like this:

import SanitySchema from '@sanity/schema';
import blockTools from '@sanity/block-tools';
import Sanity from '@sanity/client';
import { JSDOM } from 'jsdom';

const contentType = SanitySchema.compile({
    name: 'default',
    types: [
        {
            name: 'blocks',
            type: 'array',
            of: [{ type: 'block' }],
        },
    ],
}).get('blocks');

const htmlToBlocks = (html: string) => {
    return blockTools.htmlToBlocks(html, contentType, {
        parseHtml: (html) => new JSDOM(html).window.document,
    });
};

const sanity = Sanity({/* init sanity client */});

async function main() {
  const allPosts = await getAllWordPressPostsViaTheRestApi();

  const t = sanity.transaction();

  for (const post of allPosts) {
    t.createOrReplace({
      _id: post.id.toString(),
      content: htmlToBlocks(post.content.rendered),
    });
  }

  await t.commit();
}

main().catch(e => {
  console.error(e);
  process.exit(1);
});
i haven’t tested the above but i think it gives the idea
awesome. thanks
i’ll definitely check it out
Apologies if this is old hat but
user Y
’s demo, while it hasn't been updated in some time, may be helpful!
https://github.com/kmelve/wordpress-to-sanity

Sanity – Build the way you think, not the way your CMS thinks

Sanity is the developer-first content operating system that gives you complete control. Schema-as-code, GROQ queries, and real-time APIs mean no more workarounds or waiting for deployments. Free to start, scale as you grow.

Was this answer helpful?