How We Migrated a Simple Production Project to Strapi v5
If you’re as enthusiastic about Strapi as we are at Notum, you probably know that version 5 is now available in beta. As early adopters of new Strapi versions and features, we were curious about the migration process from v4 to v5 and what challenges we might face.
This is crucial for us since we were among the companies with the best know-how on migrating from v3 to v4. That migration was quite complex, but we successfully transitioned many projects, including the Strapi.io website.
We acknowledge that migrating to v5 is not yet recommended because it’s still in beta, so please take this article with a grain of salt. It’s meant for informational purposes, and the migrated project will not be run in production.
Pro tip: If you’re short on time, there’s a summary at the end of the article.
The Upgrade Tool
The Strapi team aims to simplify the migration process by introducing an upgrade tool that performs codemods to automate a large portion of the process.
However, when we ran the npx @strapi/upgrade major
command as instructed by the documentation, we received an error: "Requirement failed: You're already on the latest major version (v4)." Therefore, we won't be using the upgrade tool in this article. It will likely work when the production version is released.
We attended a community call where Strapi team showcased the upgrade tool, and it looked very promising, so we have high hopes.
About the Project
Our goal was to test the migration process on a small and simple project first. We chose a client’s website — https://www.podnikavecesko.cz/. The project includes a few collections but encompasses everything a typical Strapi project would: dynamic zones, components, relations, custom roles, and a few lifecycles with custom logic.
It runs on Strapi version 4.22.1 and is coupled with a Next.js frontend in a turbo mono repo. We use PostgreSQL as the database. In this article, we’ll attempt to migrate the Strapi application to version 5.0.0-beta.7 and see if everything works as expected.
The Migration Process
To begin, we created a fresh v5 project in a different directory to see what had changed. After a brief check, we found that the folder structure and all important files were quite similar, so we decided to upgrade the version of Strapi and other packages made by the Strapi team, such as @strapi/plugin-users-permissions
.
Before reinstalling the dependencies, it’s important to delete the .strapi
, dist
, node_modules
, yarn.lock
, and cache
directories to ensure that everything from v5 is installed.
When running the yarn
command to install all dependencies, we encountered several warnings about incorrect peer dependencies, primarily mentioning react-router-dom
and styled-components
. So, we upgraded those to version 6.0.0, the beta uses from 5.3.3 we were running.
With this resolved, it was time to build the admin panel. As expected, we faced numerous TypeScript errors. Upon inspection, we found that they were mostly type errors or unused @ts-expect-error
directives.
After removing the unused @ts-expect-error
directives and exploring the Strapi package to find the correct type imports (some were removed as we couldn't locate them), we rebuilt the application.
Yet another error appeared. This one was perplexing because we had the same dependencies installed as the fresh v5 project in its package.json
. We tweaked the dependencies, but nothing worked. So, as any developer would, we searched to see if others had encountered the same issue, and indeed, we found a solution.
The mono-repo setup might be the problem, as others reported similar issues with this setup according to a GitHub issue. So, we took a radical step and copied the entire src
directory into another freshly created v5 beta project and added the necessary dependencies to the package.json
.
After rebuilding the application again, we still received an error message. However, this time we identified the cause: the @strapi/helper-plugin
was deprecated. This package is commonly used by many plugins in the Strapi market, so they probably won't work with v5 yet. Our only option was to remove these plugins from package.json
and plugins.ts
, which we did.
Once the plugins were removed, the build was finally completed without issues. So, we started the application by running yarn develop
. When running the application for the first time, note that a few migrations run automatically.
The application started without problems, and we were pleasantly surprised that almost everything in the admin panel worked as expected. The data in our collections was intact, and the custom roles, user management, and other important features worked fine.
We only noticed a few minor issues. Our page was changed to draft even though it had been published, and we couldn’t see or edit some fields even when logged in as super admin. After checking the permissions in the database, everything seemed set up correctly, so this might be a bug in the permissions beta plugin.
Database Migration
The Strapi team did an excellent job with automated migrations. Comparing the v4 and v5 databases, we noticed many table names were shortened. For example, “components” is now “cmps” in v5.
Additionally, v5 now uses document_ids
, which were automatically generated for our existing content. Therefore, there's not much to worry about regarding the database.
Migrating the Strapi Codebase
Since our project is very simple and the backend doesn’t contain much custom logic, it started without any problem. If your project is more complex, it might not start up, and you might need to adjust the code first.
In our projects, we used the lifecycle and EntityService API, both of which work differently in v5.
Unfortunately, we found that when updating a document via the admin panel, the lifecycles weren’t triggered at all. The way they are triggered has changed, and this will need to be migrated manually, as it won’t be handled by the codemod.
Migrating from EntityService API to DocumentService API is straightforward, as shown below. This is something that will be partially handled by the codemods, so some manual work will be needed.
This covers everything we needed to do to migrate this simple project. Unfortunately, it doesn’t work as expected due to the non-functional lifecycles, but we are confident this will be fixed in upcoming beta versions.
The Frontend
Although this article mainly covers the migration of the Strapi codebase, the frontend will need adjustments too. The significant change is that in v5, the API response is now flattened, and the document ID is expected in requests instead of just the ID.
This means that every request and handling of the response needs adjustment. However, this is a relatively simple task.
Lessons Learned
The migration process seems more convenient than the migration from v3 to v4. The Strapi team did a great job automating many tasks.
To summarize, here are the key points we learned during the process and what to watch out for:
- You might experience issues when running v5 in a mono-repo.
- If you use plugins not made by Strapi, the v5 compatible version is probably not out yet and won’t work.
- You’ll need to resolve imports that are exported (or not exported at all) differently from Strapi v5 and handle TypeScript issues.
- Database migration is automated and works well.
- Table names are shortened compared to v4. For example, “components” is now “cmps” in table names.
- There might be a bug in the
@strapi/plugin-users-permissions
5.0.0-beta.7, as we couldn't see or edit some fields even when logged in as super admin. - You will need to migrate your backend customization code, especially lifecycles and any parts of the application that use EntityService API.
- Lifecycles need to be migrated because they are triggered differently. However, in version 5.0.0-beta.7, the
afterUpdate
lifecycle wasn't triggered when we updated a document. - The frontend needs to be adjusted to accommodate the new flattened structure of the API responses, and a document ID should now be sent in requests instead of just the ID.
- The upgrade tool did not work for us yet.
Please note that your project might require additional work as we tested the migration on a very simple project. If you decide to test the migration yourself, the Strapi v5 documentation has a great resource describing the breaking changes.