# v4 plugin migration: Migrating the back end
This guide is part of the v4 plugin migration guide designed to help you migrate a plugin from Strapi v3.6.x to v4.0.x.
Migrating the back end of a plugin to Strapi v4 requires:
- updating Strapi packages
- updating content-types getters and, optionally, relations
- updating the plugin configuration
Depending on these steps, some actions can only be done manually while others can be performed automatically by scripts that modify the code, which are called codemods. The following table lists available options for each step of the migration:
Action | Migration type |
---|---|
Update Strapi packages | Automatic or manual |
Update content-types getters | Automatic or manual |
Update content-types relations | Manual |
Update configuration | Manual |
# Updating Strapi packages
🤓 v3/v4 comparison
Package names in Strapi v3 are prefixed by strapi-
.
Strapi v4 uses scoped packages.
To migrate to Strapi v4, rename all Strapi packages from strapi-package-name
to @strapi/package-name
. This needs to be done in the package.json
dependencies and anywhere the package is imported.
Strapi scoped packages can be updated automatically or manually.
# Automatic Strapi packages update
✋ CAUTION
Codemods modify the plugin source code. Before running a command, make sure you have initialized a git repo, the working tree is clean, you have pushed your v3 plugin, and you are on a new branch.
To update Strapi scoped packages automatically:
Use the
update-package-dependencies
codemod (opens new window) by running the following command:npx @strapi/codemods migrate:dependencies [path-to-strapi-plugin]
1Use the
update-strapi-scoped-imports
codemod (opens new window) by running the following command:npx @strapi/codemods transform update-strapi-scoped-imports [path-to-file | folder]
1
# Manual Strapi packages update
To update Strapi scoped packages manually:
- Rename all Strapi packages (e.g.
strapi-package-name
) inpackage.json
to@strapi/package-name
- Repeat for all instances where the package is imported.
# Updating content-types getters
🤓 v3/v4 comparison
Strapi v3 models have been renamed to content-types in Strapi v4.
If the plugin declares models, update the syntax for all getters from strapi.models
to strapi.contentTypes
. The syntax can be updated automatically or manually.
# Automatic content-types getters update
✋ CAUTION
Codemods modify the plugin source code. Before running a command, make sure you have initialized a git repo, the working tree is clean, you've pushed your v3 plugin, and you are on a new branch.
To update the syntax for content-types getters automatically, use the change-model-getters-to-content-types
codemod (opens new window). The codemod replaces all instances of strapi.models
with strapi.contentTypes
in the indicated file or folder.
To use the codemod, run the following command in a terminal:
npx @strapi/codemods transform change-model-getters-to-content-types [path-to-file | folder]
# Manual content-types getters update
To update the syntax for content-types getters manually, replace any instance of strapi.models
with strapi.contentTypes
.
💡 TIP
Strapi v4 introduced new getters that can be used to refactor the plugin code further (see Server API usage documentation).
# Updating content-types relations
PREREQUISITES
Updating content-types relations to Strapi v4 requires that the v3 models have been converted to Strapi v4 content-types (see converting models to content-types documentation).
🤓 v3/v4 comparison
Strapi v3 defines relations between content-types with the via
, model
and collection
properties in the model settings.
In Strapi v4, relations should be explicitly described in the schema.json
file of the content-types (see relations documentation).
If the plugin declares content-types with relations between them, migrating relations to Strapi v4 should be done manually in the schema of the content-types.
To update content-type relations, update the server/content-types/<content-type-name>/schema.json
file for each content-type with the following procedure:
Declare the relation explicitly by setting the
type
attribute value to"relation"
.Define the type of relation with the
relation
property.
The value should be a string among the following possible options:"oneToOne"
,"oneToMany"
,"manyToOne"
or"manyToMany"
.Define the content-type target with the
target
property.
The value should be a string following theapi::api-name.content-type-name
orplugin::plugin-name.content-type-name
syntax convention.(optional) In bidirectional relations, define
mappedBy
andinversedBy
properties on each content-type.
Example of all possible relations between an article and an author content-types
// path: ./src/plugins/my-plugin/server/content-types/article/schema.json
// Attributes for the Article content-type
"articleHasOneAuthor": {
"type": "relation",
"relation": "oneToOne",
"target": "api::author.author"
},
"articleHasAndBelongsToOneAuthor": {
"type": "relation",
"relation": "oneToOne",
"target": "api::author.author",
"inversedBy": "article"
},
"articleBelongsToManyAuthors": {
"type": "relation",
"relation": "oneToMany",
"target": "api::author.author",
"mappedBy": "article"
},
"authorHasManyArticles": {
"type": "relation",
"relation": "manyToOne",
"target": "api::author.author",
"inversedBy": "articles"
},
"articlesHasAndBelongsToManyAuthors": {
"type": "relation",
"relation": "manyToMany",
"target": "api::author.author",
"inversedBy": "articles"
},
"articleHasManyAuthors": {
"type": "relation",
"relation": "oneToMany",
"target": "api::author.author"
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
// path: ./src/plugins/my-plugin/server/content-types/author/schema.json
// Attributes for the Author content-type
"article": {
"type": "relation",
"relation": "manyToOne",
"target": "api::article.article",
"inversedBy": "articleBelongsToManyAuthors"
},
"articles": {
"type": "relation",
"relation": "manyToMany",
"target": "api::article.article",
"inversedBy": "articlesHasAndBelongsToManyAuthors"
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# Updating plugin configuration
🤓 v3/v4 comparison
Strapi v3 defines plugin configurations in a config
folder.
In Strapi v4, the default configuration of a plugin is defined as an object found in the config.js
file or in the config/index.js
file. These are then called from the entry file (see default plugin configuration documentation).
To handle default plugin configurations in Strapi v4 the recommended way:
Create the
server/config/index.js
file containing an exported object.Within the
config
object:- Define a
default
key that takes an object to store the default configuration. - (optional) Add a
validator
key, which is a function taking theconfig
as an argument.
Example of a default plugin configuration
// path: ./src/plugins/my-plugin/server/config/index.js module.exports = { default: { optionA: true }, validator: (config) => { if (typeof config.optionA !== 'boolean') { throw new Error('optionA has to be a boolean'); } }, }
1
2
3
4
5
6
7
8
9
10- Define a
In the
server/index.js
file, import the configuration and export it.Example of a default entry file
// path: ./src/plugins/my-plugin/server/index.js // ... const config = require('./config'); // ... module.exports = { // ... config, // ... };
1
2
3
4
5
6
7
8
9
10
11Make sure that Strapi is aware of the plugin's back-end interface exported from
server/index.js
by adding the following line to the<plugin-name>/strapi-server.js
entry file:// path ./src/plugins/my-plugin/strapi-server.js module.exports = require('./server');
1
2
3