Skip to main content

Data migration:Migrate SQL from Strapi v3 to v4

The database layer of Strapi has been fully rewritten in Strapi v4. This documentation is designed to highlight the breaking changes introduced in Strapi v4 that impact SQL databases, by comparing v3 and v4 table and column names, data structures and relations.

Changes can be global (impacting any table) or more limited in scope, impacting only specific tables or some Strapi plugins.

:::strapi Relations in Strapi v3 vs. v4 The v3 vs. v4 SQL relations cheatsheet is designed to help you understand the differences in model schemas and entity relationship diagrams between Strapi v3 and Strapi v4. :::

🚧 Migration scripts

Data migration scripts are currently in alpha/beta testing. Please feel free to share feedback in the dedicated forum thread.

Global changes​

Changes in column casing and timestamps columns can affect all tables.

Column name casing​

:::strapi v3 / v4 comparison In Strapi v3 column names can have different casings (e.g. PascalCase, camelCase, and snake_case).

In Strapi v4, every column name should use snake_case. :::

To migrate to Strapi v4, make sure all column names use snake_case. Attributes defined in another casing in the model schema will have their name automatically transformed to snake_case when communicating with the database layer.

Timestamps columns​

:::strapi v3 / v4 comparison Timestamps columns refer to the created_at and updated_at columns.

In Strapi v3, timestamps columns are given a default value (i.e. CURRENT_TIMESTAMP) directly by the database layer.

In Strapi v4, timestamps columns can't be renamed or disabled. :::

To migrate to Strapi v4, migrate timestamps with custom column names to the created_at and updated_at fields, and remove the default value from the table structure.

Changes impacting Strapi built-in tables​

Strapi built-in tables have a different name in v3 and v4, and Strapi v4 introduces new tables (indicated by the ✨ emoji):

Table name in Strapi v3Table name in Strapi v4
strapi_permissionadmin_permissions (see admin permissions)
strapi_roleadmin_roles
strapi_administratoradmin_users
strapi_users_rolesadmin_users_roles_links
strapi_webhooksstrapi_webhooks
core_storestrapi_core_store_settings (see core store)
(non applicable)✨ admin_permissions_role_link (see admin permissions)
(non applicable)✨ strapi_migrations
(non applicable)✨ strapi_api_tokens
(non applicable)✨ strapi_database_schema

Admin permissions​

The strapi_permission table used in Strapi v3 is named admin_permissions in Strapi v4, and is subject to the following other changes:

  • The table structure is different in Strapi v3 and Strapi v4:
Strapi v3 permissions Strapi v4 permissions
  • The role relation in Strapi v4 is handled in a join table named admin_permissions_role_links.

  • New indexes have been created for the created_by_id and updated_by_id columns of Strapi v3, with the following names:

    Column name in Strapi v3Index name in Strapi v4
    created_by_idadmin_permissions_created_by_id_fk
    updated_by_idadmin_permissions_updated_by_id_fk

Core store​

The core_store table used in Strapi v3 is named strapi_core_store_settings in Strapi v4.

The structure of the core store table remains untouched, but model definitions and content manager configurations have changed.

Model definitions​

All the rows that begin with model_def_ have been dropped and are no longer required.

Content manager configurations​

All the rows that begin with plugin_content_manager_configuration_content_types have been changed to match new unique identifiers (UIDs) and reflect table names changes. These changes include both the suffix of the key column and the uid field in the value column.

In addition to all the content-types that have been renamed (see table names changes), the following UIDs have changed:

UID in Strapi v3UID in Strapi v4
applicationapi
pluginsplugin

Permissions mapping​

The following tables list the mapping of all permissions between Strapi v3 and Strapi v4:

Permission mapping for an example "restaurant" API:

Strapi v3 typeStrapi v3 controllerStrapi v3 actionStrapi v4 action
applicationrestaurantcount(deleted)
applicationrestaurantcreateapi::restaurant.restaurant.create
applicationrestaurantdeleteapi::restaurant.restaurant.delete
applicationrestaurantfindapi::restaurant.restaurant.find
applicationrestaurantfindoneapi::restaurant.restaurant.findOne
applicationrestaurantupdateapi::restaurant.restaurant.update
applicationrestaurantcreatelocalizationapi::restaurant.restaurant.createLocalization

Permission mapping for the Users & Permission plugin:

Strapi v3 typeStrapi v3 controllerStrapi v3 actionStrapi v4 action
users-permissionsauthcallbackplugin::users-permissions.auth.callback
users-permissionsauthconnectplugin::users-permissions.auth.connect
users-permissionsauthemailconfirmationplugin::users-permissions.auth.emailConfirmation
users-permissionsauthforgotpasswordplugin::users-permissions.auth.forgotPassword
users-permissionsauthregisterplugin::users-permissions.auth.register
users-permissionsauthresetpasswordplugin::users-permissions.auth.resetPassword
users-permissionsauthsendemailconfirmationplugin::users-permissions.auth.sendEmailConfirmation
users-permissionsusercountplugin::users-permissions.user.count
users-permissionsusercreateplugin::users-permissions.user.create
users-permissionsuserdestroyplugin::users-permissions.user.destroy
users-permissionsuserdestroyall(deleted)
users-permissionsuserfindplugin::users-permissions.user.find
users-permissionsuserfindoneplugin::users-permissions.user.findOne
users-permissionsusermeplugin::users-permissions.user.me
users-permissionsuserupdateplugin::users-permissions.user.update
users-permissionsuserspermissionsgetroleplugin::users-permissions.role.getRole
users-permissionsuserspermissionsgetrolesplugin::users-permissions.role.getRoles
users-permissionsuserspermissionscreateroleplugin::users-permissions.role.createRole
users-permissionsuserspermissionsdeleteroleplugin::users-permissions.role.deleteRole
users-permissionsuserspermissionsupdateroleplugin::users-permissions.role.updateRole
users-permissionsuserspermissionsgetpermissionsplugin::users-permissions.permissions.getPermissions
users-permissionsuserspermissionsgetadvancedsettings(deleted)
users-permissionsuserspermissionscustomroute(deleted)
users-permissionsuserspermissionsgetemailtemplate(deleted)
users-permissionsuserspermissionsgetpolicies(deleted)
users-permissionsuserspermissionsgetproviders(deleted)
users-permissionsuserspermissionsgetroutes(deleted)
users-permissionsuserspermissionsindex(deleted)
users-permissionsuserspermissionssearchusers(deleted)
users-permissionsuserspermissionsupdateadvancedsettings(deleted)
users-permissionsuserspermissionsupdateemailtemplate(deleted)
users-permissionsuserspermissionsupdateproviders(deleted)

Permission mapping for the i18n plugin:

Strapi v3 typeStrapi v3 controllerStrapi v3 actionStrapi v4 action
i18ncontent-typesgetnonlocalizedattributes(deleted)
i18niso-localeslistisolocales(deleted)
i18nlocalescreatelocale(deleted)
i18nlocalesdeletelocale(deleted)
i18nlocaleslistlocalesplugin::i18n.locales.listLocales
i18nlocalesupdatelocale(deleted)

Permission mapping for the Content-Type Builder:

Strapi v3 typeStrapi v3 controllerStrapi v3 actionStrapi v4 action
content-type-builderbuildergetreservednames(deleted)
content-type-buildercomponentcategoriesdeletecategory(deleted)
content-type-buildercomponentcategorieseditcategory(deleted)
content-type-buildercomponentscreatecomponent(deleted)
content-type-buildercomponentsdeletecomponent(deleted)
content-type-buildercomponentsgetcomponentplugin::content-type-builder.components.getComponent
content-type-buildercomponentsgetcomponentsplugin::content-type-builder.components.getComponents
content-type-buildercomponentsupdatecomponent(deleted)
content-type-builderconnectionsgetconnections(deleted)
content-type-buildercontenttypescreatecontenttype(deleted)
content-type-buildercontenttypesdeletecontenttype(deleted)
content-type-buildercontenttypesgetcontenttypeplugin::content-type-builder.content-types.getContentType
content-type-buildercontenttypesgetcontenttypesplugin::content-type-builder.content-types.getContentTypes
content-type-buildercontenttypesupdatecontenttype(deleted)

Permission mapping for the Upload plugin:

Strapi v3 typeStrapi v3 controllerStrapi v3 actionStrapi v4 action
uploaduploadcountplugin::upload.content-api.count
uploaduploaddestroyplugin::upload.content-api.destroy
uploaduploadfindplugin::upload.content-api.find
uploaduploadfindoneplugin::upload.content-api.findOne
uploaduploadgetsettings(deleted)
uploaduploadsearch(deleted)
uploaduploadupdatesettings(deleted)
uploaduploaduploadplugin::upload.content-api.upload

Permission mapping for the Email plugin:

Strapi v3 typeStrapi v3 controllerStrapi v3 actionStrapi v4 action
emailemailgetsettings(deleted)
emailemailsendplugin::email.email.send
emailemailtest(deleted)

Permission mapping for the Content Manager and the Documentation plugin: All permissions were deleted.

Changes impacting Strapi plugins​

Strapi v4 introduces breaking changes that impact the table names, column names and database structures used by the Users & Permissions, Upload and Internationalization (i18n) plugins.

Users and Permissions plugin​

The tables and database structure used by the Users & Permissions plugin are different in Strapi v3 and Strapi v4:

Strapi v3:

v3

Strapi v4:

v4

Enabled permissions​

In Strapi v3, permissions are always present in the table and are duplicated for each role. A permission "A" is set for a role "X" if permission "A" has the enabled column value set to 1 (true).

In Strapi v4, permissions that aren’t enabled for any role are not present in the database table (i.e. there is no more enabled column). A permission "A" is set for a role "X" if there is:

  • a permission "A" in the table rows
  • and a row linking the role "X" to the permission "A" in the join table.

Permissions columns​

In Strapi v3, permissions are defined by 3 columns:type, controller, and action.

In Strapi v4, the type, controller and action columns are replaced by a single column named action, aggregated like the following:action = transform(type).controller.action.

For more information and specific examples, you can compare the output of the same permission in Strapi v3 users-permissions_permission and Strapi v4 up_permissions tables. :::

Upload plugin​

In Strapi v3, the polymorphic table associated to the file content-type is named upload_file_morph and has both an id and an upload_file_id attribute.

In Strapi v4, the data structure of the Upload plugin is subject to the following changes:

  • The polymorphic table is named files_related_morphs. The name includes related since it concerns the file’s related attribute defined in the model schema.
  • The id and upload_file_id columns do not exist.
  • A new column file_id is added, as a foreign key pointing to files.id.
  • An index is created for the file_id column, as files_related_morph_fk.

Internationalization (i18n) plugin​

In Strapi v4, localization tables used by the Internationalization (i18n) plugin follow the circular many-to-many relationships migration and are renamed from entities__localizations to entities_localizations_links.

Entity relationship diagram for i18n localizations in v3 Entity relationship diagram for i18n localizations in v4