Contentful → Payload
Export the Contentful space with the CLI, model collections and blocks in Payload, then import entries and download assets while Contentful is still online. Roles, apps, and preview do not come with the JSON.
Should you make this move?
Both platforms have a case. Compare what you gain with what you give up before scheduling the cutover.
Contentful
- Mature structured content APIs, localization, roles, and ecosystem support enterprise publishing
- Editors get a purpose-built publishing workflow instead of raw files
- Content-model complexity, API usage, and pricing can create significant platform dependence
- Themes, extensions, and content models add maintenance and portability constraints
Payload
- Open-source collections, blocks, and a Local API keep the content model in code you can host yourself
- Editors get a purpose-built publishing workflow instead of raw files
- There is no one-click importer, so schema, rich text, and media are a scripted project
- Themes, extensions, and content models add maintenance and portability constraints
Payload: Open-source collections, blocks, and a Local API keep the content model in code you can host yourself. This removes a major source-side concern: Content-model complexity, API usage, and pricing can create significant platform dependence.
What you lose: Mature structured content APIs, localization, roles, and ecosystem support enterprise publishing. What you inherit: There is no one-click importer, so schema, rich text, and media are a scripted project.
Jump to a section
Know the shape of the move.
This timeline assumes
- You can run contentful-export against the space and you can deploy Payload 3, self-hosted or on Payload Cloud.
- Contentful stays up until every asset in the new site is stored on your side. The export contains URLs, not a guarantee the files already sit on disk.
- The site already documents Contentful → Strapi, Contentful → Sanity, and Contentful → WordPress.
- A vendor walkthrough from Payload and 10xmedia is the public recipe. It is a partner tutorial, not a one-click importer.
- Editors do not publish in Contentful during the final import.
What survives the move.
“Partial” and “manual” are not footnotes. They are work that must be scheduled and verified.
| Item | Outcome | Impact | What happens | Mitigation |
|---|---|---|---|---|
| Content types | manual | critical | Payload's Contentful post says to export with the CLI, then create collections, blocks, and globals that match the space. There is no importer that builds the config for you. | Write the collections first. Store the Contentful entry id on each document so you can rerun. |
| Entries | partial | critical | contentful-export writes JSON. You load it with a script on the Local API. payload.find is paginated, so a check script has to page or set pagination false. | Import parents before references. Run a second pass for links. Compare totalDocs with the export count. |
| Rich text | partial | high | Contentful rich text is a document. Payload's current editor is Lexical. The Contentful post calls this out as a transform, along with media and reusable templates. | Convert one entry of every rich text field before the full run. Keep the raw export. |
| Assets | partial | critical | Asset URLs in the export point at Contentful. If you cancel the space, those images die. Upload them into a Payload upload collection. | Download during import. Check file size. Do not ship HTML that still points at Contentful's CDN. |
| Locales | manual | critical | Contentful locales and fallbacks do not become Payload localized fields by themselves. | Turn localization on for the fields that need it. Import each locale on purpose. |
| Roles, tasks, and comments | lost | high | The export is content. Contentful roles, tasks, and comments are not Payload users. | Create users and access rules in config. Archive comments if you still need them. |
| Apps, preview, and webhooks | manual | high | Contentful apps and preview URLs stay in Contentful. Payload preview is whatever you build. | Point preview at the new frontend before editors cut over. |
| Scheduled releases | lost | medium | Scheduled actions and releases are not entries in the export you can replay. | Write down future publish times and recreate them. |
| Draft and published | partial | high | A published-only export drops drafts. Payload versions are a separate feature you have to turn on. | Export the preview API as well if drafts matter. Map status yourself. |
| Frontend queries | manual | critical | Contentful's content delivery API is not Payload's Local API or REST. The frontend changes even when the fields look familiar. | Run the new site on a branch against Payload before DNS or the client switches. |
| Identifiers in URLs | manual | high | Contentful ids will not be Payload ids. Public URLs should keep using the slug. | Store the old id. Redirect only where the slug changed. |
Where each thing goes.
| Source | Destination | Method | Notes |
|---|---|---|---|
| Content type | Collection config | manual | Code, not a click-through importer. |
| Entry id | contentfulId field | transform | Use it to upsert on the next run. |
| Entry fields | Collection fields | transform | References need a second pass. |
| Rich text | Lexical | transform | Convert a sample of every field first. |
| Asset | Upload collection | transform | Download the file. Do not store only the Contentful URL. |
| Locale | Localized field | manual | Enable localization before import. |
| Slug | Slug | automatic | Keep it when the public URL should not change. |
| Tags and references | Relationship fields | transform | Import the related collection first. |
| Roles and comments | No destination | unsupported | Recreate access in Payload. Archive the comments. |
Make the move recoverable.
Create the source-of-truth backup
Keep a full contentful-export, including assets you could re-download, before Payload writes over anything.
- Run contentful-export and store the JSON with a checksum.
- Record entry counts per content type and per locale.
- List scheduled publishes and webhooks.
- Note which frontend is still reading Contentful.
- Work from a copy of the export.
Proof to capture: Checksum, per-type counts, and the name of the person who can rerun the export.
Model collections before any import
Give the script somewhere true to write.
- Create a collection per content type you are keeping.
- Add contentfulId, indexed.
- Add blocks for the modular fields the Contentful post tells you to rebuild.
- Turn on localization and uploads before the first write.
Proof to capture: Save the input, output, command or tool settings, warnings, and final item counts.
Import with the Local API
Write documents from the export without going through the admin click by click.
- Keep Contentful online so asset URLs still resolve.
- Create documents that nothing else points at.
- Second pass: set relationships now that ids exist.
- Download assets into the upload collection. Fail the row if the file is empty.
Proof to capture: Save the input, output, command or tool settings, warnings, and final item counts.
The things most likely to hurt.
These are operating limits. Treat every “Stop if” condition as a blocked migration, not a suggestion.
Assets still live on Contentful
The export stores URLs. Cancelling the space removes the files.
- Consequence
- The new site shows broken images.
- Mitigation
- Upload every referenced file and grep the built HTML for the Contentful host.
Stop if: A high-traffic page still requests images from Contentful.
References point at nothing
Ids in the export are Contentful ids. Payload ids are new.
- Consequence
- Related entries are blank.
- Mitigation
- Store contentfulId and link on a second pass.
Stop if: A sample entry is missing a relationship you did not mark as optional.
Editors publish during the run
The export is a snapshot.
- Consequence
- The last Contentful edits never arrive.
- Mitigation
- Freeze Contentful, export again, import the delta.
Stop if: Someone published after the freeze and the delta was not imported.
Do the work in this order.
- Day 1 · export
Export the space
2 to 4 hours active1 day elapsedThe export job waiting- Run contentful-export.
- Count types, locales, and assets.
- List what you will not migrate.
Stop / go checkpointIs the snapshot complete?
Go when: Counts match the space and the file is stored.
Stop when: A locale or a content type is missing.
- Days 2 to 4 · model
Write collections
1 to 2 days active3 days elapsedNone waiting- Add collections, blocks, and globals.
- Add contentfulId and localization.
- Stand up an empty admin and create the first user.
Depends on: export
Stop / go checkpointCan the script write?
Go when: A sample of every type has a field to land in.
Stop when: Rich text or uploads are still undecided.
- Days 5 to 7 · import
Import entries and assets
1 to 2 days active3 days elapsedAsset downloads waiting- Import independent documents.
- Link relationships.
- Upload media and record failures.
Depends on: model
Stop / go checkpointDo counts match?
Go when: totalDocs matches the export, with a written exception list.
Stop when: Missing relationships or empty files are unexplained.
- Day 8 · preview
Read the site from Payload
4 hours active1 to 3 days elapsedFrontend branch waiting- Point a branch at Payload.
- Check slugs, locales, and image hosts.
- Have an editor open the admin.
Depends on: import
Stop / go checkpointIs the branch good enough to freeze Contentful?
Go when: Sample pages match and no image host is Contentful.
Stop when: A locale or a template is wrong.
- Day 9 · cutover
Freeze and switch readers
2 hours active1 day elapsedThe delta import waiting- Stop Contentful publishes.
- Export and import the delta.
- Send production reads to Payload.
Depends on: preview
Stop / go checkpointStay on Payload?
Go when: Delta counts match and the sample pages still pass.
Stop when: An editor published into the old space after the freeze.
Cut over with a way back.
Cutover
Serve the site from Payload with Contentful frozen and assets off Contentful's CDN.
- Tell editors the space is read-only. Record the time.
- Export again and import only new or changed ids.
- Re-check image hosts and a page per locale.
- Point the frontend at Payload.
- Keep the Contentful export. Do not cancel the space the same day.
Proof to capture: Freeze time, delta counts, and a page sample with image hosts.
Rollback
Point the frontend back at Contentful if Payload content or assets are wrong.
- Point the frontend back at Contentful.
- Leave the Payload database as it is so you can diff it.
- If editors wrote in Payload, export those documents before you discard them.
- Re-open Contentful publishing only after the site is confirmed.
- Write down which ids were created only in Payload.
Proof to capture: The live site reads Contentful again and the Payload-only edits are listed.
- A sample page is missing a relationship.
- Images still load from Contentful on a page you called done.
- A locale is empty.
- The delta after freeze was not imported.
Prove the migration worked.
Every blocking check must pass. Capture the evidence before cleanup begins.
| Pass | ID | Check | Method | Expected result | Evidence |
|---|---|---|---|---|---|
CNT-01Blocking | Entry counts | Compare contentful-export counts with payload.find totalDocs per collection. | Counts match or the exception list names every skip. | The count table. | |
REL-01Blocking | Relationships | Open 10 entries that had references. | Each reference resolves. | The entry ids. | |
IMG-01Blocking | Image hosts | Grep built HTML and the database for the Contentful asset host. | No production URL remains. | The grep output. | |
LOC-01Blocking | Each locale | Open one entry per locale. | The localized fields are filled. | Screenshots or the document JSON. | |
RT-01Blocking | Lexical sample | Compare one rich text field per content type with Contentful. | Headings, links, and embeds you care about survived. | Side-by-side notes. | |
SLG-01Blocking | Slugs | Compare slug fields on a sample. | Unchanged slugs match. Changed ones have a redirect. | The slug diff. | |
EDT-01 | An editor can sign in | Have a non-developer open admin and save a draft. | The draft saves and does not publish itself. | The draft id. | |
FRZ-01Blocking | Freeze held | Compare Contentful updatedAt values with the freeze time. | No publish after the freeze, or it is in the delta. | The timestamp check. |
Remove the scaffolding safely.
Safe after: The frontend has read Payload for a week, image hosts are clean, and editors have published once in Payload.
- Archive the contentful-export outside both systems.
- Revoke the Contentful tokens the script used.
- Keep the space readable until the retention date.
- Remove Payload users created only for the import.
- Set the next review date.
When the plan met reality.
First-hand accounts are preferred. Vendor case studies are labeled, and every note below is an editorial paraphrase—follow the link for the full context.
Focus Reactive, an agency, says Glimble, a mobility product in the Netherlands, left Contentful for a self-hosted Payload project on Next.js. They describe the old schema as close enough that the content move was relatively straightforward, and they used the project to rebuild components and fix bugs. The writeup claims 49 or more components migrated, 30 or more new ones, and five admin roles, plus a translation flow that went from weeks of manual work to days with an AI draft and a human review. Treat those figures as the agency's account.
- Budget time to rebuild components even when the agency calls the schema compatible.
- If translation is why you are leaving, design the review step before you import locales.
- A Contentful to Payload move can be a component rebuild, not a file conversion.
- The published numbers come from the agency that did the work, not from Glimble's own post.
Verify against the primary material.
Platform behavior changes. Check these sources and the review dates above before executing a production migration.
- Contentful: CLI import and exportAccessed 2026-11-06
- Payload: migrate from ContentfulAccessed 2026-11-06
- Payload: Local APIAccessed 2026-11-06
- Payload: queriesAccessed 2026-11-06
- Focus Reactive: Glimble Contentful to Payload case studyAccessed 2026-11-06