DEV Community

Cover image for What is New for Developers in Strapi 5: Top 10 Changes
Theodore Kelechukwu Onyejiaku for Strapi

Posted on • Originally published at strapi.io

What is New for Developers in Strapi 5: Top 10 Changes

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
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

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
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

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 the Strapi-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:

Strapi 5 Response without Strapi 4 Headers.png

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.

Strapi 5 with v4 Response format.png

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",
});
Enter fullscreen mode Exit fullscreen mode

Using the Document Service:

// Using the Document service
strapi.documents(uid).findMany({
  fields: ["id", "name", "description"],
  populate: ["author", "comments"],
  status: "draft",
});
Enter fullscreen mode Exit fullscreen mode

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:

fetch entry by id.png
id is used in Strapi v4 API calls

However, in Strapi 5, using the documentId, the following response is returned:

fetch entry by documentid.png
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>;
Enter fullscreen mode Exit fullscreen mode

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 Migration on Github.png
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.

Strapi Data Manipulation with TypeScript.png
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
Enter fullscreen mode Exit fullscreen mode

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),
});
Enter fullscreen mode Exit fullscreen mode

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:
Strapi draft entry.png
Draft Version of an Entry

Strapi published entry.png
Published Version of an Entry

We will get this when we make a GET request to get the draft version.

fetch Draft Version in Strapi.png
Fetch Draft version in Strapi

You get this when you set the status query parameter to published.

fetch Published Version in Strapi.png
Fetch Published Version in Strapi

✏️ Note
The published version gets returned when you do not specify the status query parameter.

count()

The count() function fetches the number of documents that match the provided parameters.

await strapi.documents('api::restaurant.restaurant').count()
Enter fullscreen mode Exit fullscreen mode

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',
});
Enter fullscreen mode Exit fullscreen mode

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",
  });
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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.

Strapi 5 uses Vite.png
Strapi 5 uses Vite

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.

Strapi Docs AI Chatbot

👋 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 official Strapi demo App.jpg
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:

Try LaunchPad Today

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.

Top comments (0)