Why move from Contentful to Payload CMS?
Teams move from Contentful to Payload to own their content and stop paying along Contentful's tier boundaries. Payload is open source, self-hosted and lives in the same codebase as a Next.js front end, so content types, locales and editors don't change the license bill.
Our research found that Contentful's tier jumps, such as the 25-content-type ceiling on a smaller space tier noted in Pagepro's write-up, push teams toward Sanity or Payload. Payload is the choice when the team also wants a typed, code-defined schema next to the front end. We run Payload in production on our own site, and this guide reflects that. For the general method, see our headless CMS migration hub, and to compare the hosted alternative, read Contentful to Sanity migration.
Contentful | Payload | |
|---|---|---|
Hosting | Vendor-hosted SaaS | Self-hosted, inside your Next.js app |
Database | Vendor-managed | Your Postgres or MongoDB |
Schema | Defined in the web app or scripts | TypeScript config in your repo |
Rich text | Rich text JSON | Lexical JSON by default |
Cost shaped by | Spaces, content types, locales, seats | Your hosting, database and storage |
How do Contentful concepts map to Payload?
Contentful concepts map to Payload with few gaps: content types become collections, singletons become globals, link fields become relationship fields and assets become an upload collection. The meaningful change is page building, where Payload's blocks field replaces chains of referenced section entries.
Contentful | Payload | Migration note |
|---|---|---|
Content type | Collection | Define fields in TypeScript |
Single entry used as settings | Global | Navigation, footer, site settings |
Reference to section entries | Blocks field | Inline sections instead of separate entries |
Link field | Relationship field | Import referenced docs first |
Asset | Upload collection | Re-upload files to your storage |
Localized field | Field with localized set to true | Enable locales in the config |
Environment | Separate database or deployment | Schema changes move to git |
Moving sections into blocks simplifies the model a lot. A landing page that was a page entry with ten references to section entries becomes one document with an array of typed blocks. Editors find it easier, and queries no longer resolve deep link chains. Our guide to content modeling for CMS migrations covers how to make that kind of change deliberately.
How do you run a Contentful to Payload migration step by step?
You run a Contentful to Payload migration by setting up Payload in your Next.js app, defining the schema, exporting from Contentful, transforming the data and importing with a script that uses Payload's Local API. Keep the export as files so you can re-run the transform and import as often as you need.
Set up Payload in your Next.js app
Add Payload to the app, connect a Postgres or MongoDB database and configure storage for uploads.
Define collections, globals and blocks
Write the schema in TypeScript, improving on the Contentful model rather than copying it. Turn on localization if you need it.
Export from Contentful
Use the Contentful CLI's space export to save entries, assets and locales as JSON.
Import media first
Download every asset and create it in the upload collection, recording a map of Contentful asset IDs to Payload IDs.
Import documents in dependency order
Create referenced documents such as authors and categories first, then pages and posts, storing the Contentful ID on each.
Patch relationships
Run a second pass that fills relationship fields using the ID map, so circular references don't fail.
Switch queries and validate
Replace Contentful API calls with Local API calls in server components, then check counts, references and rendered pages.
How do you convert Contentful rich text to Payload's Lexical format?
You convert Contentful rich text to Payload by mapping each Contentful node to a Lexical node, either directly in a script or by going through HTML with Payload's rich text converters. Direct mapping is more work and keeps embedded entries intact.
Paragraphs, headings, lists, quotes, links and bold or italic marks have clear Lexical equivalents. Embedded assets become upload nodes pointing at your re-uploaded media. Embedded entries, such as a callout box or a code sample, become Lexical blocks you define in the editor config. Inline entry links become internal link nodes with a relationship. For a deeper comparison of HTML, Markdown and structured formats, see migrating rich text between CMSs.
Choosing between the direct and HTML routes
The HTML route renders Contentful rich text to HTML with Contentful's renderer, then converts that HTML to Lexical with Payload's converters. It's quick for plain articles and needs little custom code. Check Payload's current rich text docs for the converters available in your version.
The direct route walks Contentful's JSON tree and builds Lexical JSON node by node. It takes longer to write, but embedded entries and entry links come through as real blocks and relationships instead of markup.
A practical approach is to use the HTML route for posts with no embeds and the direct route for everything else. Scan the export first to see which articles contain embedded nodes.
How do you handle localization when moving to Payload?
You handle localization by enabling Payload's localization config with the same locale codes as Contentful, marking the right fields as localized, and writing each locale's value during import. Contentful and Payload both localize at the field level, so the data shape is close.
In Contentful's export, a localized field is an object keyed by locale code. In Payload, you create the document in the default locale, then update it once per additional locale with that locale's values. Keep locale codes identical so your front-end routes don't change. Decide how fallbacks should work, since Payload can fall back to the default locale when a translation is missing, and match whatever your Contentful setup did. If you're moving localized content from WordPress instead, our WordPress to Sanity or Payload guide covers the plugin-based patterns.
What changes after you leave Contentful for Payload?
After leaving Contentful, you own the infrastructure: database, backups, media storage, upgrades and access control. In return, your schema is typed code in your repo, content reads are local function calls and your bill depends on hosting rather than content types or seats.
Pros
- No license cost tied to content types, locales or editors
- Content lives in your database
- Typed schema reviewed in pull requests
- Local API reads with no network hop
- Admin panel lives at a route in your own app
Cons
- Backups and database upgrades are your job
- No vendor support desk unless you buy one
- Editors learn a new admin
- Fewer marketplace apps than Contentful
Plan editor training and a short period of running both systems. Our notes from production in setting up Payload CMS for a marketing site and CMS setup for marketing websites cover how to give editors page-building freedom in the new admin. If you're moving from another CMS to Payload, see Sanity to Payload and Strapi to Payload.
