A headless CMS splits content from presentation: your articles, pages, and custom records live in an API-first system, Sanity, Contentful, Strapi: and your front end (Next.js, Astro, Nuxt, a mobile app) pulls them over an API. You get speed, a clean content model, omnichannel delivery, and a much smaller attack surface than a WordPress install.
The front end is the fun part, and it’s well-trodden. The hard part of going headless is the migration: reshaping years of WordPress content (posts, custom post types, taxonomies, ACF fields) into the new CMS’s schema without losing data or rankings. This guide is about that part.
Why go headless
Teams move WordPress to a headless CMS for a handful of durable reasons: a structured content model instead of a soup of HTML, an API that feeds a website and an app and a kiosk from one source, performance from a static or edge-rendered front end, and security from not exposing wp-admin to the world. If those are why you’re here, the migration is worth doing carefully, because a headless CMS only pays off if your content lands in it cleanly structured.
Headless CMS vs headless WordPress, pick your path
“Going headless” means two different things, and they involve very different amounts of migration:
- Headless WordPress: keep WordPress as the backend and serve content through WPGraphQL or the REST API to a separate front end. Almost no migration: your content stays put. You keep WordPress’s editing experience, but also its hosting and maintenance.
- A dedicated headless CMS: replace WordPress entirely with Sanity, Contentful, or Strapi. A real migration, but a clean break: no more WordPress to maintain, and a content model you design.
If you just want a faster front end and are happy keeping WordPress, headless WordPress is the lighter route. If you want off WordPress, you’re doing a content migration, read on.
Map your content model first
This is the step that makes or breaks the project, and it happens on paper before you export anything. WordPress organizes content as post types (posts, pages, your CPTs), taxonomies (categories, tags, custom ones), and custom fields (ACF/JetEngine/Pods). Your headless CMS organizes it as schemas, Sanity document types, Contentful content types, Strapi collection types.
Map them one to one:
- Each WordPress post type → a schema/content type in the CMS.
- Each ACF field → a field on that schema, with a matching data type.
- Each taxonomy → either a reference to its own document type or a simple array of tags.
- Relationships (post → author, service → category) → references between documents.
Get this mapping right and the rest is scripting. Skip it and you’ll be re-typing content by hand.
Get your content out of WordPress
You need structured data, not a wall of HTML. That means an export where each item is an object with its fields separated out (title, slug, permalink, SEO, custom fields, and the body) so a script can map field to field. JSON is the natural format:
{
"type": "services",
"title": "Corneal Cross-Linking",
"slug": "corneal-cross-linking",
"permalink": "https://old-site.com/services/corneal-cross-linking/",
"seo": { "title": "…", "description": "…" },
"fields": { "duration_minutes": 30, "recovery": "1–2 days" },
"content_html": "<h2>What is it?</h2><p>…</p>"
}
Two things matter here. First, the body must be rendered: if your pages use a builder, a raw export gives you shortcodes, not content. Second, custom fields should be resolved: an image field should be a real media object (URL, alt, dimensions), not a bare attachment ID the new CMS can’t interpret.
Migratik is the clean input a headless import needs
Migratik exports your whole site as structured JSON, every post type as an object with its fields separated, rendered content, resolved ACF/JetEngine/Pods values (image fields as real media objects), SEO meta, and permalinks for redirects. It’s builder-agnostic and read-only. Free to install; the media bundle that brings your images along is Pro.
Transform to the CMS’s shape
With structured JSON in hand, a transform script maps each exported item onto a CMS document. The one conversion you can’t skip is rich text: Sanity wants Portable Text, Contentful wants its rich-text JSON, and Strapi takes HTML or Markdown. Your exported content_html has to be converted into the target’s format, there are libraries for each (for example, HTML-to-Portable-Text for Sanity). Everything else (scalar fields, references, media) is straightforward key-to-key mapping.
Import into Sanity, Contentful, or Strapi
Each CMS gives you an import path:
- Sanity: create documents through
@sanity/client, or bulk-load an NDJSON file with the Sanity CLI. - Contentful: use the
contentful-importtool with a structured import file, or the Management API. - Strapi: post to the REST API, or seed through a script against its content types.
A minimal Sanity import loop looks like this:
// import.mjs: one document per exported item
import { createClient } from '@sanity/client';
import data from './migratik-export.json' with { type: 'json' };
const client = createClient({
projectId: 'xxxxxxxx', dataset: 'production',
token: process.env.SANITY_TOKEN, useCdn: false,
});
for (const item of data.items) {
await client.create({
_type: item.type,
title: item.title,
slug: { current: item.slug },
body: item.content_html, // convert to Portable Text for a real run
});
}
Run it against a dev dataset first, check a few documents in the studio, then run it for real.
Move the media
Images referenced by URL still point at /wp-content/uploads/ until you move them. In a headless CMS, media become first-class assets: Sanity assets, Contentful uploads, Strapi media, so your import needs to upload each file and relink the reference. Trying to pull images one-by-one from the live WordPress mid-import is fragile; a media bundle exported alongside the content (every file packaged, URLs rewritten) makes the upload step reliable and repeatable.
Keep your SEO through the move
Going headless doesn’t change the SEO rules, only your front end serves pages, so the front end has to carry them. Keep your URLs, 301-redirect anything that changes, and reproduce each page’s title, meta description, and canonical from the exported metadata. That’s why the export must include SEO fields and the old permalinks. For the front-end side of doing this without losing rankings, our Next.js and Astro guides walk through redirects, metadata, and sitemaps step by step.
Do the model mapping thoughtfully and start from a clean structured export, and a headless migration stops being a data-entry marathon and becomes what it should be: a transform script you run once.
Frequently asked questions
Can I migrate WordPress to a headless CMS like Sanity or Contentful?
Yes. Export your WordPress content as structured data (JSON), map each field to the target CMS’s schema, then import via the CMS’s API or import tool. The main work is matching your content model, not moving the text.
What’s the difference between headless WordPress and a headless CMS?
Headless WordPress keeps WordPress as the backend and serves content over an API (WPGraphQL / REST) to a separate front end. A headless CMS replaces WordPress entirely with an API-first system like Sanity, Contentful, or Strapi. The first is less migration; the second is a cleaner break.
How do I move ACF custom fields to a headless CMS?
Recreate each field in the CMS’s schema, then map the exported ACF values into it during import. Export the ACF data resolved to real values (image fields as media objects, not raw attachment IDs) so the import has something usable.
Will going headless affect my SEO?
Only your front end serves pages, so SEO depends on rebuilding it correctly: keep your URLs, 301-redirect anything that changes, and carry over titles, meta descriptions, and canonicals. Export that metadata from WordPress so your new front end can reproduce it.
Export the structured content a headless CMS needs
Migratik turns your whole WordPress site into clean structured JSON (rendered content, resolved custom fields, media, and SEO) the exact input a Sanity, Contentful, or Strapi import script wants. Free to install, read-only, safe on a live site.