
Migrating to Strapi 5 is a full rework, not a version bump. This guide walks you through every essential step — including the new Document ID model, Document Service API, and plugin migration — with real examples and upgrade instructions.
1. Prepare your environment
Step 1 — Backup
Back up your Strapi 4 project:
# Save your DB pg_dump mydb > backup.sql # Backup source code cp -r my-strapi4-project my-strapi4-backup
Step 2 — Note custom code
List everything custom:
/src/plugins/src/extensionsModified controllers/services
Step 3 — Check versions
Strapi 5 requires Node.js ≥ 18.
Ensure your dependencies are compatible (
npm outdated).
2. Create a clean Strapi 5 project
You cannot “upgrade in place”. Instead, create a new project:
npx create-strapi-app@latest my-strapi5-project
Then copy over:
/src/api(content types, controllers, services)/src/plugins(custom ones only)/config(migrated progressively)
You’ll refactor them step by step below.
3. Migrate Content Types
Step 1 — Adjust schemas
Open one of your Strapi 4 schema files, e.g.:
Strapi 4:
{ "kind": "collectionType", "info": { "displayName": "Article" }, "attributes": { "title": { "type": "string" }, "content": { "type": "text" }, "author": { "type": "relation", "relation": "manyToOne", "target": "api::user.user" } } }
Strapi 5:
{ "kind": "collectionType", "info": { "displayName": "Article" }, "options": { "draftAndPublish": true }, "attributes": { "title": { "type": "string" }, "content": { "type": "text" }, "author": { "type": "relation", "relation": "manyToOne", "target": "api::user.user" } } }
Changes:
Use
documentIdinternally (Strapi manages this automatically — you no longer use numericid).Draft & Publish is now integrated into all content types.
4. Migrate from Entity Service → Document Service
Strapi 4 used:
await strapi.entityService.findMany('api::article.article', { filters: { title: 'Hello' } });
Strapi 5 now uses:
await strapi.documents('api::article.article').findMany({ filters: { title: 'Hello' }, status: 'published', // "draft" or "published" });
Step 1 — Search & Replace
Globally replace strapi.entityService with strapi.documents.
Step 2 — Update IDs
Replace references to .id with .documentId if you manually use identifiers in code.
Step 3 — Adjust queries
publishedAtis replaced bystatus: 'published'.Pagination and filters are almost identical, but more consistent.
5. Update Plugins
Step 1 — Remove helper-plugin
@strapi/helper-plugin is deprecated.
Replace all imports:
import { request } from '@strapi/helper-plugin';
→
import { request } from '@strapi/strapi/admin';
Step 2 — Adapt plugin API
Your custom plugin should now have:
src/plugins/my-plugin/ ├── strapi-admin.js ├── strapi-server.js └── package.json
In strapi-server.js:
export default () => ({ register() {}, bootstrap() {}, });
Step 3 — Use Document Service
Update all data logic in plugins to use strapi.documents() instead of entityService.
6. Update Config & Middlewares
Configuration files changed syntax slightly.
Strapi 4:
module.exports = ({ env }) => ({ host: env('HOST', '0.0.0.0'), port: env.int('PORT', 1337), });
Strapi 5:
import { defineConfig } from '@strapi/strapi'; export default defineConfig({ host: process.env.HOST || '0.0.0.0', port: parseInt(process.env.PORT) || 1337, });
Do the same for:
/config/database.js/config/middlewares.js/config/plugins.js
7. Migrate Data
If your content is simple (no relations, few entries), export & reimport:
# Export from Strapi 4 curl https://strapi4.example.com/api/articles?populate=* > articles.json
Then use a small script to push them to Strapi 5:
const axios = require('axios'); const data = require('./articles.json'); for (const item of data.data) { await axios.post('https://strapi5.example.com/api/articles', { data: { title: item.attributes.title, content: item.attributes.content, }, }); }
For larger databases, you’ll need to write SQL migration scripts adding documentId columns.
8. Reconfigure Roles & Permissions
In Strapi 5:
Roles and Permissions are tied to Document lifecycle actions.
Each content type now supports actions like
read,create,publish,unpublish.
After migration:
Go to Settings → Roles & Permissions.
Re-enable access for each route.
Re-test your public/private API endpoints.
9. Test and Deploy
npm run develop
Check:
Admin panel loads.
All content types appear.
APIs respond with the new
documentId.Plugins work without helper-plugin errors.
Then deploy following Strapi 5’s official deployment guide.