Entity Service API to Document Service API migration reference
In Strapi 5, the Document Service API replaces the Entity Service API from Strapi v4 (see breaking change description).
The present page is intended to give developers an idea of how to migrate away from the Entity Service API, by describing which changes in custom code will be handled by codemods from the upgrade tool and which will have to be handled manually.
It is strongly advised not to upgrade a critical or production-ready project from Strapi v4 to Strapi 5.
The content of migration resources might not be final yet. Migration resources are currently only provided to prepare you for the upgrade to Strapi 5 when it is released as a stable version.
Strapi 5 is currently only provided as a Release Candidate (RC) version and is not meant to be used in production yet.
Migration using the upgrade tool
When using the upgrade tool, a codemod is run and handles some parts of the entityService
migration.
The codemod is only changing the function calls and some parameters. This can not be considered as a complete migration as the codemod will never be able to convert an entityId
into a documentId
.
Codemod scope
The following list explains what is automatically handled by the codemod (✅), what is not handled by the codemod and must be handled 100% manually (❌) and what will still require manual intervention after the codemod has run (🚧):
Topic | Handled by the codemod? | Manual steps to perform |
---|---|---|
Code structure | ✅ Yes | Nothing. The code structure is automatically migrated. |
publicationState removed in favor of status | ✅ Yes | Nothing. The codemod automatically transforms it. |
Usage of documentId instead of the Strapi v4 unique identifiers | 🚧 Partially:
| 👉 __TODO__ placeholder values need to be manually updated.For instance, you might change documentId: "__TODO__" to something like documentId: "ln1gkzs6ojl9d707xn6v86mw" . |
Update of published_at to trigger publication | ❌ Not handled. | 👉 Update your code to use the new publish() , unpublish() , and discardDraft() methods of the Document Service API instead. |
Examples of function calls migration
The following examples show how the codemod from the upgrade tool updates the code for various function calls.
findOne
Before:
strapi.entityService.findOne(uid, entityId);
After:
strapi.documents(uid).findOne({
documentId: "__TODO__"
});
findMany
Before:
strapi.entityService.findMany(uid, {
fields: ["id", "name", "description"],
populate: ["author", "comments"],
publicationState: "preview",
});
After:
strapi.documents(uid).findMany({
fields: ["id", "name", "description"],
populate: ["author", "comments"],
status: "draft",
});
create
Before:
strapi.entityService.create(uid, {
data: {
name: "John Doe",
age: 30,
},
});
After:
strapi.documents(uid).create({
data: {
name: "John Doe",
age: 30,
},
});
update
Before:
strapi.entityService.update(uid, entityId, {
data: {
name: "John Doe",
age: 30,
}
});
After:
strapi.documents(uid).update({
documentId: "__TODO__",
data: {
name: "John Doe",
age: 30,
}
});
delete
Before:
strapi.entityService.delete(uid, entityId);
After:
strapi.documents(uid).delete({
documentId: "__TODO__"
});
count
Before:
strapi.entityService.count(uid);
After:
strapi.documents(uid).count();
Manual migration
-
Users who prefer to manually migrate can do so by replicating what the codemod does (see codemod scope and function calls examples for reference).
-
Plugin developers who use Entity Service decorators in their code must replace them by Document Service middlewares. The following example gives you an idea of how they work, and additional information can be found in the dedicated Document Service middlewares documentation:
In Strapi v4:
strapi.entityService.decorate((service) => {
return Object.assign(service, {
findOne(entityId, params = {}) {
// e.g., exclude soft deleted content
params.filters = { ...params.filters, deletedAt: { $notNull: true } }
return service.findOne(entityId, params)
}
});
})In Strapi 5
strapi.documents.use((ctx, next) => {
if (ctx.uid !== "api::my-content-type.my-content-type") {
return next();
}
if (ctx.action === 'findOne') {
// customization
ctx.params.filters = { ...params.filters, deletedAt: { $notNull: true } }
const res = await next();
// do something with the response if you want
return res;
}
return next();
});
-
Update your custom code for
findMany()
on single types, taking into account that:- In Strapi v4, the
findMany()
function returns a single item when called on a single type. - In Strapi 5, the
findMany()
function is generic and always returns arrays, whether called on a single type or on a collection type. To get data for a single type with afindMany()
call, extract the first item from the returned array.
- In Strapi v4, the