← All playbooks
CMS migration

Payload → Strapi

Model Strapi content types to match your Payload collections, then copy documents with a script. Strapi's import file is for Strapi data, not a Payload database dump.

Typical timeline1 to 2 weeksA few days active work
Statusneeds review
Source profilePayload Local API and pagination docs reviewed 2026-11-06
Destination profileStrapi data import docs reviewed 2026-11-06
Documentation date
Review window
Evidence4 sources
This route needs review.Use it as a planning baseline, then verify the dated sources and test with representative data before production.
Before you migrate

Should you make this move?

Both platforms have a case. Compare what you gain with what you give up before scheduling the cutover.

Current platform

Payload

Reasons to stay
  • 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
Reasons to leave
  • 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
New platform

Strapi

What gets better
  • An open-source headless CMS with a writable admin, REST, GraphQL, and a readable export archive
  • Editors get a purpose-built publishing workflow instead of raw files
What gets worse
  • Self-hosting, schema code, and custom importers become your problem when you leave a SaaS CMS
  • Themes, extensions, and content models add maintenance and portability constraints
Best of the move

Strapi: An open-source headless CMS with a writable admin, REST, GraphQL, and a readable export archive. This removes a major source-side concern: There is no one-click importer, so schema, rich text, and media are a scripted project.

Worst of the move

What you lose: Open-source collections, blocks, and a Local API keep the content model in code you can host yourself. What you inherit: Self-hosting, schema code, and custom importers become your problem when you leave a SaaS CMS.

Jump to a section
01At a glance

Know the shape of the move.

Transfer outcome11 features audited
Transfer outcome distributionClean transfer: 0, Partial transfer: 4, Manual rebuild: 5, Not transferred: 2.
Clean0
Partial4
Manual5
Lost2
Mapping route8 of 9 fields have a destination path

This timeline assumes

  • Strapi 5 is empty, or you are writing into types you created for this move. strapi import expects Strapi's own archive.
  • You can read Payload with the Local API. find is paginated unless you turn pagination off.
  • The site already documents Payload → WordPress, and Strapi → Payload is not this guide.
  • Admin users and API tokens are not part of a Strapi content export. Create them again.
  • Payload stays online until uploads have been copied into Strapi.
02What transfers

What survives the move.

“Partial” and “manual” are not footnotes. They are work that must be scheduled and verified.

ItemOutcomeImpactWhat happensMitigation
Collection configmanualcriticalPayload collections are TypeScript. Strapi content-types are their own schema. Nothing reads one and writes the other.Create the Strapi types first. Keep field names close when you can. Add a payloadId field.
DocumentspartialcriticalYou page through payload.find and create Strapi documents through the document service or REST. Strapi import will not accept the Payload database.Compare totalDocs with the Strapi count. Upsert on payloadId so you can rerun.
Blocks and LexicalpartialhighPayload blocks and Lexical do not match Strapi's blocks or rich text. You convert them.Convert one document of each shape. Store the raw field if you may need it.
UploadspartialcriticalFiles live on Payload's disk or adapter. Strapi needs them in its upload plugin.Upload the bytes. Do not leave Strapi fields pointing at Payload's file host.
RelationshipsmanualhighIds change. A relationship has to be rewritten after both documents exist.Import targets first. Second pass sets relations.
LocalizationmanualhighPayload localized fields are not Strapi i18n locales until you enable the plugin and import each locale.Enable i18n on the types that need it. Import locale by locale.
Access and userslosthighPayload access is code. Strapi export skips admin users and API tokens. Editors need new accounts.Recreate roles in Strapi admin. Send new logins.
GlobalsmanualmediumA Payload global is one document. Strapi uses a single type for the same idea, and you create it.Make a single type for header and footer and copy the fields.
HookslosthighPayload hooks do not become Strapi lifecycles. Side effects stop unless you port them.List hooks that send mail or sync another system. Port the ones you need.
Drafts and versionspartialmediumTaking only published documents drops draft history. Strapi draft-and-publish is a flag you set on the type.Turn the flag on before import if editors need drafts. Map status on purpose.
Frontend clientmanualcriticalThe app is calling Payload's API. Strapi's REST or GraphQL shape is different even when field names match.Point a branch at Strapi before you cut readers over.
03Field and feature mapping

Where each thing goes.

SourceDestinationMethodNotes
CollectionStrapi content-typemanualCreate it before the script runs.
Document idpayloadIdtransformThe upsert key.
FieldsAttributestransformKeep names when the types match.
Lexical or blocksRich text or Strapi blockstransformConvert. Do not paste JSON into a string field and call it done.
UploadMedia librarytransformCopy bytes, then relate.
RelationshipRelationtransformSecond pass.
Localei18n localemanualEnable the plugin first.
GlobalSingle typemanualOne document.
Access functionNo destinationunsupportedRebuild roles.
04Before you begin

Make the move recoverable.

Backup procedure

Create the source-of-truth backup

Keep a Payload dump and, once Strapi has data, a Strapi export that you can restore.

  1. Dump the Payload database and copy uploads.
  2. Record totalDocs per collection.
  3. After a successful import, run a Strapi export and store it. That archive is for Strapi, not for Payload.
  4. Note that the Strapi export omits admin users and API tokens.
  5. Keep checksums.

Proof to capture: Payload dump checksum, totalDocs, and the later Strapi export checksum.

Transformation · Strapi content-type builder or schema files

Create Strapi types

Give every Payload collection a destination.

  1. Add a type per collection you are keeping.
  2. Add payloadId as a unique string.
  3. Enable i18n and draft-and-publish only where you need them.
  4. Create the media library before the script uploads.

Proof to capture: Save the input, output, command or tool settings, warnings, and final item counts.

Transformation · payload.find and the Strapi document API

Copy documents

Move rows without pretending strapi import understands Payload.

  1. Page until you have read totalDocs.
  2. Create documents that have no relations.
  3. Upload files and store the new media ids.
  4. Update relations. Write failures to a file.

Proof to capture: Save the input, output, command or tool settings, warnings, and final item counts.

05Handle with care

The things most likely to hurt.

These are operating limits. Treat every “Stop if” condition as a blocked migration, not a suggestion.

Import

Someone feeds Payload JSON to strapi import

criticalpossible likelihood

Strapi import reads a Strapi export archive.

Consequence
The import fails, or you think it loaded content when it did not.
Mitigation
Use a script. Reserve strapi import for a Strapi-to-Strapi restore.

Stop if: The only artifact you have is a Payload database dump and no script log.

Export

The first page of 10 is the whole migration

criticallikely likelihood

find returns 10 documents unless you page.

Consequence
Most of the site never arrives.
Mitigation
Log totalDocs against rows written.

Stop if: Those numbers differ.

Media

Files still sit on Payload

highlikely likelihood

Relations can store a URL instead of an uploaded file.

Consequence
Turning off Payload breaks images.
Mitigation
Upload bytes and search Strapi for the old host.

Stop if: A sampled page still loads media from Payload.

06Precise timeline

Do the work in this order.

Estimate forOne Payload app, one new Strapi 5 project, scripted copy
Total elapsed1 to 2 weeks
Active workA few days
BufferLocales and blocks add a conversion pass.
01
Day 1Count and dump1 day
02
Days 2 to 3Strapi types2 days
03
Days 4 to 6Copy documents3 days
04
Day 7Point a branch at Strapi1 to 3 days
05
Day 8Freeze and switch1 day
  1. Day 1 · inventory

    Count and dump

    3 hours active1 day elapsedNone waiting
    • Record totalDocs.
    • Dump Payload and copy uploads.
    • List blocks and relations.
    Stop / go checkpoint

    Is the backup real?

    Go when: The dump restores on a scratch database, or you have tested a table count.

    Stop when: Uploads were not copied.

  2. Days 2 to 3 · schema

    Strapi types

    1 day active2 days elapsedNone waiting
    • Create types and payloadId.
    • Enable i18n if you need it.
    • Create an admin user.

    Depends on: inventory

    Stop / go checkpoint

    Can you create one document by hand?

    Go when: A sample type accepts a document and a file.

    Stop when: The type builder is still changing field names.

  3. Days 4 to 6 · copy

    Copy documents

    1 to 2 days active3 days elapsedUploads waiting
    • Create plain documents.
    • Upload media.
    • Set relations.

    Depends on: schema

    Stop / go checkpoint

    Do counts match?

    Go when: Strapi counts match totalDocs, with a written skip list.

    Stop when: The script only logged one page.

  4. Day 7 · client

    Point a branch at Strapi

    4 hours active1 to 3 days elapsedFrontend work waiting
    • Read a sample through Strapi.
    • Check locales and image hosts.
    • Have an editor open Strapi admin.

    Depends on: copy

    Stop / go checkpoint

    Is the branch acceptable?

    Go when: Sample pages match and media is local to Strapi.

    Stop when: A relation or a locale is empty.

  5. Day 8 · cutover

    Freeze and switch

    2 hours active1 day elapsedDelta copy waiting
    • Stop Payload writes.
    • Copy the delta.
    • Send the app to Strapi.
    • Take a Strapi export.

    Depends on: client

    Stop / go checkpoint

    Stay on Strapi?

    Go when: The delta matches and the Strapi export is stored.

    Stop when: Payload changed after the freeze.

07The point of change

Cut over with a way back.

Go live

Cutover

Read production content from Strapi, with Payload frozen and files off Payload's storage.

Recommended window: After the branch passes, with the script owner available for one delta.

  1. Freeze Payload. Record the time.
  2. Copy documents changed after that time.
  3. Re-check image hosts.
  4. Switch the app.
  5. Run strapi export and store the archive. It is your Strapi backup, not a Payload file.

Proof to capture: Freeze time, counts, and the Strapi export checksum.

Return to safety

Rollback

Point the app back at Payload if Strapi content is incomplete.

Deadline: While Payload is still deployed. The Strapi export does not restore Payload.

  1. Point the app at Payload.
  2. Leave Strapi data in place.
  3. Copy any Strapi-only edits back if editors used it.
  4. Re-open Payload.
  5. Keep the Strapi export anyway.

Proof to capture: The app reads Payload and Strapi-only edits are listed.

Rollback immediately when
  • Counts do not match totalDocs.
  • A sampled relation is empty.
  • Media still loads from Payload.
  • A locale is missing.
08Verification report

Prove the migration worked.

Every blocking check must pass. Capture the evidence before cleanup begins.

0%
Interactive report preview0 / 8 checks passed
PassIDCheckMethodExpected resultEvidence
CNT-01BlockingtotalDocsCompare each collection with the Strapi count.They match or the skip list explains the gap.The table.
PAG-01BlockingAll pages were readRead the script log for pages and totalDocs.Rows read equals totalDocs.The log.
REL-01BlockingSample relationsOpen 10 documents that had relationships.Each relation resolves.The ids.
MED-01BlockingOld host is goneSearch Strapi for the Payload file host.Sampled content does not use it.The search.
LOC-01BlockingLocalesOpen one document per locale.Fields are filled.The documents.
RICH-01BlockingOne of each blockCompare rendered output with Payload admin.Sections you listed are present.The comparison.
ADM-01BlockingEditor loginSign in as a new Strapi user and save.The save works. The API token used for import is not the editor's password.The user id.
BAK-01Strapi export existsConfirm the export file opens and is stored outside the server.The archive is present and its checksum is written down.The checksum.
09Post-migration cleanup

Remove the scaffolding safely.

Safe after: The app has read Strapi for a week and a Strapi export is stored.

  1. Keep the Payload dump until the retention date.
  2. Revoke import tokens.
  3. Leave Payload read-only, then shut it down when the date arrives.
  4. Remember the Strapi export has no admin users.
  5. Set the next review date.
Sources and evidence

Verify against the primary material.

Platform behavior changes. Check these sources and the review dates above before executing a production migration.

  1. Payload: Local APIAccessed 2026-11-06
  2. Payload: paginationAccessed 2026-11-06
  3. Strapi: data importAccessed 2026-11-06
  4. Strapi: data exportAccessed 2026-11-06