Strapi, the leading open-source headless CMS, has always been a favorite among developers. It is known for its great features, such as modern API creation, content management and collaboration, effortless coding, and intuitive publishing. With the release of Strapi 5, there are now a host of exciting new features and improvements.
Whether you're migrating from a previous version or starting fresh, as a developer, understanding these changes is important to leveraging Strapi 5's full potential. Here are the Top 10 Changes developers need to know about in Strapi 5.
1. New API Response Format
We are glad to say that data.attributes
are no longer used. API responses are now simplified and flattened.
In Strapi v4, requested content data are wrapped inside an attributes
key. A typical API response of v4 would look like this:
// Strapi v4 API Response:
{
"data": {
// system fields
"id": 14,
"attributes": {
// user fields
"title": "Article A",
"relation": {
"data": {
"id": "clkgylw7d000108lc4rw1bb6s",
"attributes": {
"name": "Category A"
}
}
}
}
},
"meta": {
"pagination": {
"page": 1,
"pageSize": 10
}
}
}
In Strapi 5, the attributes are no longer nested and are present directly in the data object. The Content API returns attributes of requested content without wrapping them in an attributes object:
// Strapi v5 API Response
{
"data": {
// system fields
"documentId": "clkgylmcc000008lcdd868feh",
"locale": "en",
// user fields
"title": "Article A",
"relation": {
// system fields
"documentId": "clkgylw7d000108lc4rw1bb6s",
// user fields
"name": "Category A"
}
},
"meta": {
"pagination": {
"page": 1,
"pageSize": 10
}
}
}
Notice the introduction of the documentId
, which we will discuss shortly.
✏️ Note
To use the old format of v4 in your Strapi 5 project, set theStrapi-Response-Format: v4
in your project. We will see this in action below.
Want to use Strapi v4 Response?
To use the previous Strapi v4 response, you will have to set the header of your response to Strapi-Response-Format: v4
.
When we fetch an entry in Strapi 5, this is the response we get:
As we can see in the image above, the response header doesn't contain the Strapi-Response-Format: v4
header. Also, notice the absence of the attributes
object in the response.
Let's add it to the Strapi-Response-Format: v4
header.
From the image above, we can see that when we add the Strapi-Response-Format: v4
to our API request headers, we will get the response in Strapi v4 format.
2. Document Service Replaces Entity Service
In Strapi 5, documents are introduced. Documents are all the entities that make up the different locales, drafts, historical versions, etc.
Using the Entity service, grouping and managing every bit of the same piece of content, such as localization, publication status, and content history, became very complicated and inefficient.
Some of Strapi 5's new features, including Draft and Publish with Content History, are made possible and efficient through the Document service. Otherwise, complex processes like an extra Join table would be created, making queries complex and slow.
Here is an example of how a query could be made using the Entity Service instead of the Document Service.
Using the Entity Service
// Using the Entity Service
strapi.entityService.findMany(uid, {
fields: ["id", "name", "description"],
populate: ["author", "comments"],
publicationState: "preview",
});
Using the Document Service:
// Using the Document service
strapi.documents(uid).findMany({
fields: ["id", "name", "description"],
populate: ["author", "comments"],
status: "draft",
});
In the first code, the strapi.entityService.findMany()
is used to find multiple entries that match the provided parameters. The publicationState
parameter is a string that specifies the publication state of the entries to return. In this case, it is set to "preview", which means both draft entries and published entries will be returned (more details here).
In the second code, the status
parameter is a string that specifies the publication status of the documents to return. In this case, it is set to "draft"
, which means only draft documents will be returned (source).
In terms of syntax, the Document Service and Entity Service are very similar. However, in the new Strapi 5, there are new functions such as count()
, which we will see soon.
→ You can check out the Entity Service API to Document Service API migration reference.
3. documentId
instead of Id
In v4, you would want to make use of the id
of an entry for every API call (REST API and GraphQL API. This was possible through the use of the Entity Service API.
For instance, you would want to get an entry by its id
and get the following response:
id
is used in Strapi v4 API calls
However, in Strapi 5, using the documentId
, the following response is returned:
Use documentId
for every API call in Strapi 5.
API calls to entries might still include an id
field in their response, especially with the Document Service API. But it's recommended that you start using documentId
instead of id
, as it will ease handling the transition to future Strapi versions.
4. TypeScript
In Strapi 4, applications could be created using TypeScript. An experimental typed system for APIs and automated typed generation for content types and components were also included.
Type System in Strapi 5
With TypeScript support, Strapi 5 improved the type system with pure type names for APIs and better namespace organization. This will allow you to import the namespaces that you need using the correct types for your API. It also means that each type from the type system has a description and example of how to use it.
import type {Data, Schema, UID, Utils} from "@strapi/strapi";
// ...
declare function fetch<T extends UID.Schema>(uid: T) : Data.Entity<T>;
declare function getComponentSchemas(): Utils.String.Dict<Schema.Component>;
TypeScript Code Migration
Strapi was initially written in plain JavaScript. In Strapi 5, the code base is almost entirely written in TypeScript. One benefit is TypeScript support for user-facing APIs, which will improve over time.
Strapi TypeScript Code Migration
Data Manipulation
With 100% TypeScript support in Strapi 5, you won't need to check which method, filter, or data type is expected.
Data manipulation with TypeScript
From the image above, we can see that the Document Service API provides us with access to many methods provided by TypeScript support.
5. Upload a file at Entry Creation No Longer Supported
In Strapi 5, creating an entry while uploading a file is no longer possible. The recommended steps are done in two steps.
Step 1: You must upload the file first
The first step to take is to upload the file. Once uploaded, make sure to get its id
. This will be the id
of the file for the entry.
// upload file
const file_upload_response = await fetch(`${StrapiURL}/api/upload`, {
method: 'post',
body: formData
});
// create entry with file id
const id = file_upload_response[0].id
Step 2: Create an Entry with the File id
When you get the id
of the file as shown above, the next step is to create the entry using the id
of the file. An example is shown below:
// upload file
const file_upload_response = await fetch(`${StrapiURL}/api/upload`, {
method: 'post',
body: formData
});
// Get the uploaded file id
const id = file_upload_response[0].id
// create new entry using the file id
const newEntry = {
data: {
entryName: data.name,
entryFile: id // file id
}
}
// Invoke API Call to create new entry
const response = await fetch(`${StrapiURL}/api/{collection}`, {
method: 'post',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(newEntry),
});
6. New Functions and Query for Draft and Publish Using
The introduction of Draft and Publish brought in some new functions for Document Service API. Here are a few of them.
- Fetch the published or draft version of an entry with the
status
query parameter. count()
publish()
unpublish()
discardDraft()
The Publication Status
When you make a GET
request to fetch an entry in Strapi 5 using the status
parameter. You can choose between a published entry or draft version by specifying the status
query parameter as published
or draft
.
Imagine we have a draft and published versions of an entry as shown in the two images below:
Draft Version of an Entry
We will get this when we make a GET
request to get the draft version.
You get this when you set the status
query parameter to published
.
Fetch Published Version in Strapi
✏️ Note
The published version gets returned when you do not specify thestatus
query parameter.
count()
The count()
function fetches the number of documents that match the provided parameters.
await strapi.documents('api::restaurant.restaurant').count()
publish()
With the publish()
function, you can publish one or multiple locales of a document. This method only works if Draft and Publish is enabled.
await strapi.documents('api::restaurant.restaurant').publish({
documentId: 'a1b2c3d4e5f6g7h8i9j0klm',
});
A Typical Scenario
Let's say we want to find an article written in one language, English, and published in another, French.
This is what you can do:
// find the English version of the article
const article = await strapi.documents("api::article.article").findFirst({
locale: "en",
filters: {
title: { $contains: "health" },
},
status: "draft",
});
// if article exists, publish it in French
if (article) {
await strapi.documents("api::article.article").publish({
documentId: article.documentId,
locale: "fr",
});
}
→ Learn more about the Document Service API along with its functions
7. The new Plugin SDK
Strapi 5 introduces the new Plugin SDK, a CLI tool. Although there are many ways to create plugins in Strapi, it is recommended that you use the Plugin SDK.
With the Plugin SDK, you do not need to set up a Strapi project before creating a plugin. You can create Strapi plugins in 3 steps:
Step 1: Create a new plugin at a given path.
Start by creating a new plugin.
npx @strapi/sdk-plugin init my-strapi-plugin
In the command above, the my-strapi-plugin
represents whatever you want to call your plugin.
Step 2: Link the plugin to your project
cd /path/to/strapi/project
npx yalc add --link my-strapi-plugin && npm install
Ensure you are inside your Strapi project before running the npx
command above. Also, have yalc installed globally.
Also, recall that my-strapi-plugin
is the name of your plugin or package and not a folder.
Step 3: Bundle the Strapi plugin for publishing.
With the plugin ready to be published, the next step is to build the plugin.
npm run build && npm run verify
With the command above, you can safely build and verify that the plugin is ready to be published.
→ You can check out the Plugin SDK reference to learn more.
8. Vite is the default bundler in Strapi 5
Previously, Strapi used Webpack, a free and open-source module bundler for JavaScript.
Because performance and stability are very crucial, we switched to Vite.
Here are some benefits Vite provided:
- Faster Dev Mode, which leverages esbuild, a Go-based tool, to bundle code faster than traditional JavaScript-based bundlers.
- Zero-config approach, which Vite uses, thereby saving time to focus on building and not configuring.
- Future improvements of Vite will no doubt be a game changer in improving Strapi’s performance and flexibility.
9. AI-based Chatbot
The documentation page now has an AI-based chatbot with which you can interact and ask questions. This chatbot, powered by Kapa.ai, is designed to assist users by answering their questions in real time.
👋 Attention
Please ensure you double-check the information provided by a chatbot.
10. LaunchPad
LaunchPad is now the official Strapi’s new demo app, designed to showcase Strapi 5’s capabilities with a modern frontend and advanced features.
LaunchPad, the official Strapi Demo App
Built to replace FoodAdvisor, which has been your go-to demo app to explore Strapi’s capabilities, reaching 1K+ stars on GitHub, it comes with a modern tech stack:
- Strapi 5
- Next.js 14
- Aceternity UI
- Tailwind CSS
Want to Learn More About the New Changes and Features in Strapi 5?
Strapi 5 introduced other new and breaking changes. Here are a few resources you can check out.
Strapi v4 to Strapi 5 breaking changes
Visit the Strapi Docs for more information on breaking changes.
Improved Content Editing Experience - Strapi 5 Draft, Publish, & Content History.
Join Marc Roig and Rémi de Juvigny from Strapi to learn how to streamline your content workflow with Strapi 5's new Draft & Publish and Content History features.
Improved Performance - Strapi 5 Vite & TypeScript
In this video, Alex and JS from Strapi talk about the improvements in performance with Vite and TypeScript support.
Improved Content Editing Experience - Strapi 5 Draft, Publish, & Content History
Learn how to streamline your content workflow with Strapi 5's new Draft & Publish and Content History features with Marc Roig and Rémi de Juvigny from Strapi.
Conclusion
So far, we have looked at the new Strapi 5 and its interesting new features, such as Draft and Publish, Vite bundler, TypeScript support, and more. We also discussed some changes, such as the Document Service API replacing the Entity Service, the documentId
for API calls, the new AI-based chatbot, the new way of creating Strapi plugins using the Plugin SDK, the official new Strapi 5 demo app called LanchPad, and so on.
To learn more about the new Strapi 5, visit the Strapi headless CMS documentation page.
Thank you for all the community support and contributions.