How to Migrate a WordPress Site to a Headless CMS: A Practical Walkthrough

Moving a content-heavy site off WordPress sounds simple in a Trello card and brutal at 2 a.m. when you discover that 4,000 posts have inline base64 images and a custom shortcode no one documented. If you’re planning to migrate WordPress to a headless CMS like Strapi, Sanity, Hygraph, or Cosmic, this guide focuses on the decisions and traps that the average tutorial skips.

We’ve shipped several of these migrations at adproductstogo.com, and below is the workflow we actually use, including the parts that hurt.

Why teams move from WordPress to a headless CMS

Before touching a single export file, be honest about why you’re migrating. The reason changes the architecture.

  • Performance: ship a static or ISR front-end on Next.js, Nuxt, or Astro.
  • Multi-channel publishing: feed a website, a mobile app, and a kiosk from the same content API.
  • Developer experience: typed schemas, Git-based workflows, modern preview pipelines.
  • Security and maintenance: less plugin sprawl, fewer 3 a.m. CVE patches.

If your only goal is “WordPress feels slow”, a good cache layer might be cheaper than a full migration. If you need structured content reused across channels, headless is the right call.

headless cms migration

Step 1: Audit before you export

Most failed migrations skip this step. Run a real content audit before exporting anything.

  1. List every post type: posts, pages, custom post types (CPTs), ACF groups, taxonomies.
  2. Crawl the live site with Screaming Frog or Sitebulb. Save the URL list, status codes, canonicals, and meta tags.
  3. Export your top 200 URLs from Google Search Console. These are the ones whose ranking you absolutely cannot lose.
  4. Identify shortcodes, Gutenberg blocks, and embedded HTML that won’t survive a clean export.
  5. Check media: total size, hotlinks, missing alt text, WebP/AVIF coverage.

Decide your target schema now

Headless CMSs reward structured content. Don’t replicate the WordPress “one big HTML field” model in Strapi or Sanity. Break a Post into clean fields: title, slug, excerpt, hero image, body (portable text or blocks), author reference, categories, SEO object.

Step 2: Pick the right destination

There is no universal winner. Match the CMS to the team.

CMS Best for Watch out for
Strapi Self-hosted, full control, custom roles You own infra, upgrades, backups
Sanity Rich content, Portable Text, real-time collab GROQ learning curve, usage-based pricing
Hygraph GraphQL-first, federated content Less plugin ecosystem
Cosmic / Contentful Marketing-friendly UIs, fast onboarding Cost scales with editors and API calls

Step 3: Export WordPress content cleanly

You have three realistic options:

  • WP REST API (recommended): paginated, predictable JSON, can include ACF fields with the right plugin.
  • WPGraphQL: cleaner queries, great for selective field extraction.
  • WXR XML export: works for tiny sites, breaks fast on anything custom.

Sample REST extraction loop

GET https://yoursite.com/wp-json/wp/v2/posts?per_page=100&page=1&_embed

The _embed flag pulls featured media, author, and taxonomy in one call, which saves thousands of round-trips on a large site.

The shortcode and Gutenberg trap

The REST API returns rendered HTML, but shortcodes that depend on PHP runtime (forms, sliders, related posts) will return broken markup. Decide per shortcode:

  • Replace with a structured field (e.g., a Gallery component).
  • Replace with a front-end component in your Next.js or Nuxt app.
  • Strip and rewrite manually for high-value pages.
headless cms migration

Step 4: Transform and import

Write a Node.js script. Don’t try to do this in a no-code tool unless your site has fewer than 50 posts.

  1. Fetch posts in batches from the WP API.
  2. Map fields to your new schema (title, slug, body, seo, etc.).
  3. Convert HTML to Portable Text (Sanity) or keep it as rich-text blocks (Strapi).
  4. Upload media to the new CMS or to a CDN like Cloudinary or Bunny, and rewrite image URLs in the body.
  5. Recreate references: authors, categories, tags. Create them before importing posts so foreign keys resolve.
  6. Push to the CMS via its CLI or API. Sanity has sanity dataset import, Strapi has its REST/import plugin.

Handle media properly

Media is where migrations bleed time. Recommendations:

  • Download every /wp-content/uploads/ asset locally first. Don’t trust the live server to be available during cutover.
  • Preserve filenames so old uploads/ URLs can be 301-redirected to the new CDN paths.
  • Generate WebP/AVIF variants in the new pipeline rather than importing legacy JPEG soup.
  • Re-attach alt text. WordPress stores it on the attachment, not in the post HTML, so your transformer needs to fetch it explicitly.

Step 5: Preserve SEO (the part that decides if the project is a success)

Losing rankings is the number one regret in headless migrations. Lock these down:

URL structure

Match your existing slugs exactly. If WordPress used /category/post-slug/, replicate it in your front-end router. If you must change patterns, build a 301 map.

Redirect map

Old URL New URL Type
/2022/03/old-slug/ /blog/old-slug 301
/?p=1234 /blog/resolved-slug 301
/wp-content/uploads/img.jpg https://cdn.site.com/img.jpg 301

Meta and structured data

  • Export Yoast or Rank Math meta into a dedicated seo object on each entry.
  • Rebuild JSON-LD (Article, BreadcrumbList, Organization) on the front-end.
  • Regenerate sitemap.xml and robots.txt from the new CMS data, not from the framework defaults.
  • Keep canonical tags self-referential unless you intentionally consolidate.

Step 6: Stage, QA, and cut over

  1. Deploy the headless front-end to a staging domain blocked by robots.txt and basic auth.
  2. Run a Screaming Frog crawl on staging. Compare title tags, H1s, meta descriptions, status codes against the old crawl.
  3. Validate Core Web Vitals on representative pages.
  4. Smoke-test forms, search, comments (Disqus, Giscus, or custom), and analytics.
  5. Schedule the cutover during low-traffic hours. Switch DNS, deploy redirects, submit the new sitemap in Google Search Console.
  6. Monitor 404s daily for two weeks. Patch the redirect map as needed.
headless cms migration

Pitfalls we keep seeing in 2026

  • Forgetting feed URLs: /feed/ still gets traffic from aggregators. Generate a new RSS endpoint.
  • Author archives: WordPress generates them automatically, headless does not. Either rebuild or 301 to the homepage.
  • Search: WP’s built-in search disappears. Plug in Algolia, Meilisearch, or Pagefind.
  • Comments: decide early whether to migrate, archive read-only, or drop them.
  • Editorial shock: editors used to the WP block editor will resist. Budget time for training and good preview URLs.
  • Preview environments: configure draft preview before launch, not after editors complain.

Should you keep WordPress as the back-end?

One pragmatic middle path: run headless WordPress with WPGraphQL feeding a Next.js front-end. You keep the editor your team knows, gain a modern front-end, and avoid a full content migration. It’s a valid stop on the road to a fully decoupled CMS, and sometimes it’s the final destination.

FAQ

How long does it take to migrate WordPress to a headless CMS?

For a 100-page marketing site, two to four weeks including QA. For a 5,000-post publication with custom fields and complex media, plan for two to four months.

Will my Google rankings drop?

Not if URLs match, redirects are in place, meta data is preserved, and Core Web Vitals improve. Most well-executed migrations see rankings hold or rise within 30 to 60 days.

Strapi or Sanity for a WordPress migration?

Choose Strapi if you want self-hosting, predictable costs, and a familiar admin UI. Choose Sanity if your content is rich, collaborative, and benefits from Portable Text and GROQ queries.

Can I migrate without downtime?

Yes. Build the new site on a staging subdomain, run both in parallel, then swap DNS. Use a short TTL (300 seconds) the day before the swap.

What about WooCommerce?

WooCommerce is a different beast. Migrating product content to a headless CMS while keeping WooCommerce as the commerce engine, or moving to Shopify/Medusa, is a separate project. Don’t bundle it with a content migration unless you have to.

Final thought

A headless migration is 20% code and 80% content decisions. Audit hard, model your schema before exporting, treat redirects as a first-class deliverable, and don’t ship until a full crawl matches. Do that, and the move from WordPress to a headless CMS becomes a performance win instead of an SEO regret.