# v4 code migration: Updating controllers
This guide is part of the v4 code migration guide designed to help you migrate the code of a Strapi application from v3.6.x to v4.0.x.
🤓 v3/v4 comparison
In both Strapi v3 and v4, creating content-types automatically generates core API controllers. Controllers are JavaScript files that contain a list of methods, called actions.
In Strapi v3, controllers export an object containing actions that are merged with the existing actions of core API controllers, allowing customization.
In Strapi v4, controllers export the result of a call to the createCoreController
factory function, with or without further customization.
Migrating controllers to Strapi v4 consists in making sure that each controller is located in the proper folder and uses the createCoreController
factory function introduced in v4.
Due to the differences between controllers implementation in Strapi v3 and v4, it's recommended to create a new controller file, then optionally bring existing v3 customizations into the new file and adapt them when necessary.
✏️ NOTE
The controller file can be created automatically with the interactive CLI command strapi generate
.
To create a v4 controller:
Create a
api/<api-name>/controllers/<controller-name>.js
file inside the./src
folder (see project structure).Copy and paste the following code at the top of the
./src/api/<api-name>/controllers/<controller-name>.js
file. The code imports thecreateCoreController
factory function from the factories included with the core of Strapi:const { createCoreController } = require('@strapi/strapi').factories;
1Copy and paste the following code, replacing
api-name
andcontent-type-name
with appropriate names. The code exports the result of a call to thecreateCoreController
factory function, passing the unique identifier of the content-type (e.g.api::api-name.content-type-name
) as an argument:module.exports = createCoreController('api::api-name.content-type-name')
1(optional) To customize controller actions, pass a second argument to the
createCoreController
factory function. This argument can be either an object or a function returning an object. The object contains methods, which can either be entirely new actions or replace or extend existing actions of core API controllers (see controllers implementation documentation).
Example of a v4 controller without customization:
// path: ./src/api/<content-type-name>/controllers/<controller-name>.js
const { createCoreController } = require('@strapi/strapi').factories;
module.exports = createCoreController('api::api-name.content-type-name');
2
3
4
5
Example of a v4 controller with customization:
// path: ./src/api/<content-type-name>/controllers/<controller-name>.js
const { createCoreController } = require('@strapi/strapi').factories;
module.exports = createCoreController('api::api-name.content-type-name', ({ strapi }) => ({
// wrap a core action, leaving core logic in place
async find(ctx) {
// some custom logic here
ctx.query = { ...ctx.query, local: 'en' }
// calling the default core action with super
const { data, meta } = await super.find(ctx);
// some more custom logic
meta.date = Date.now()
return { data, meta };
},
}));
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
💡 Customization tips
- The original controller’s CRUD actions can be called using
super
(e.g.super.find()
). - The
sanitizeInput
andsanitizeOutput
utilities can be used in Strapi v4 and replace thesanitizeEntity
utility from v3.
More examples can be found in the controllers implementation documentation.
🤓 Next steps
Migrating the back end code of Strapi to v4 also requires to at least migrate the core features of the Strapi server, such as the configuration, dependencies, routes, services, and content-type schemas.