What Are Strapi Policies And Customizations?

Related Articles

Multi-Agent Systems for Real Estate: How AI Teams Are Reshaping Property Operations in 2026

How Agentic AI Is Transforming Real Estate Operations in 2026





A headless content management system called Strapi is used to create backend apps. Strapi lets you personalize your backend with policies, middleware, controllers, services, models, and webhooks if you know how to code in JavaScript.
You will discover more about policies and their application in this post. Now let’s get going!
Consider going into a bank and wanting to deposit money there. Banks, as you may know, have restrictions that limit what you are allowed to carry into the institution. To make sure that no one breaks any policies, the bank may install security checks at its entry.
Security will advise you to leave the facility and address the problem if it isn’t already worse if you break a policy. The security lets you into the building as long as you don’t break any rules.
Requests in computing use routes to deliver data to the server. Requests enter through the routes. You can set up policies with Strapi to verify these requests at a route before they reach the server. For a request to be approved, it must not contravene any policies.
Strictly speaking, a policy is a function that establishes a rule for each request that comes into the server. The request is accepted by the server if the function returns true. The request is denied if the function returns false. Policies that contain your unique regulations can be created.
? Strapi Generators policy: Produce an API policy
Policy name: primary policy
? Where would you like to see this policy added? Put a policy at the project’s foundation.
++ /policies/first-policy.js
✨ Completed in 28.56 seconds.
First-policy, a global policy I recently developed, is located in the src/policies folder.
This is an illustration of a file that is generated automatically:
module.exports = (config, { strapi }, policyContext) => {
// Here, add your own reasoning.
(“In first-policy policy.”); strapi.log.info;
const canDoSomething is set to true.
suppose (canDoSomething) {
return the truth;
~
return a false positive;
};
I’m going to add one more console as well.log into our policy to make it more visible.
(“In first-policy policy.”); strapi.log.info;
The global policy number is #################; console.log(“#################”);
You can use the npx create-strapi-app@latest my-project –quickstart to create your Strapi app right now if you haven’t already. Once your project has been created, proceed as indicated below.

To proceed with the project, you must configure an API that enables data manipulation and access from outside apps into Item. There will be routes in the API for obtaining, adding, changing, and removing data.

To enable public users to get, edit, add, and remove data from this item, click Select All.
To make the changes go into effect, click save.
Now that we have our endpoint tested, we can use Postman or Insomnia.
Alternatively, we can test it locally in the browser by going to http://localhost:1337/api/items if we are doing a GET request.
This is the answer we receive.
~
“information”: [
~
“id”: a single
“characteristics”: {
“name” : “Desk” ,
“code” : “98932” ,
“cost”: $10.99,
“createdAt” : “2023-09-06T17:01:53.934Z” ,
“updatedAt” : “2023-09-06T17:01:54.508Z” ,
“publishedAt” : “2023-09-06T17:01:54.507Z”
~
~
],
“meta”: {
“pagination”: {
“page”: one
“pageSize”: 25
“pageCount”: one
“total”: one
~
~
~
Linking a worldwide policy to a path
Let’s now register the newly established policy to a route. This can be done in the API configuration file for the route.
configuration: {
locate: {
regulations: [
/ refer to a legally registered policy
“global::first-policy” ,
// direct the user to a registered policy with unique settings
// { config: {} }, name: “global::policy-name”,
// directly pass the policy function
// (config, { strapi }, policyContext) => {
// give a true response;
// },
],
~,
~,
});
We should try again with a GET request to http://localhost:1337/api/items to see if our policy is generating the console log message.
Our policy’s log ought to be visible in the console right now.
Information from [2023-09-06 12:15:03.337]: In the initial policy.
International Policy #################
[2023-09-06 12:15:03.341] GET /api/items (13 ms) 200
To launch our Strapi application in an interactive shell environment, use the yarn strapi console.
The strapi.policies program can then be used to view all of the available policies.
The output that follows should be visible.
~
“admin::isAuthenticatedAdmin”: [Anonymous Function],
“admin::possessesPermissions”: {
the name ‘admin::hasPermissions’,
validator: [WrappedValidator function],
handler: [The handler’s function]
~,
If “admin::isTelemetryEnabled,” then {
calling it ‘admin::isTelemetryEnabled’,
validator: [WrappedValidator function],
handler: [The handler’s function]
~,
‘global::first-policy’: [Anonymous Function],
‘plugin::content-manager.possesses-draft-and-publish’: [Anonymous Function],
‘content-manager.hasPermissions.plugin’: {
The plugin ‘plugin::content-manager.hasPermissions’
validator: [WrappedValidator function],
handler: [The handler’s function]
~
~
You can view the global policy we developed.
manually establishing a worldwide policy
The yarn strapi generate command just creates a boilerplate-filled./src/policies/[policy-name].js file.
You can manually repeat the action.
Make a file called./src/policies/[policy-name].js to establish a policy. Optionally, you can paste a boilerplate to begin going more quickly. As an illustration:
“use strict” ;
module.exports = (config, { strapi }, policyContext) => {
// Here, add your own reasoning.
“In the policy.” – strapi.log.info;
const canDoSomething is set to true.
suppose (canDoSomething) {
return the truth;
~
return a false positive;
};
Global::policy-name is the reference for global policies. Different references apply to different kinds of policies.
“use strict” ;
module.exports = (config, { strapi }, policyContext) => {
// Here, add your own reasoning.
“In the policy.” – strapi.log.info;
const canDoSomething is set to true.
suppose (canDoSomething) {
return the truth;
~
return a false positive;
};
Global::policy-name is the reference for global policies. Different references apply to different kinds of policies.
Now let’s examine the creation of API policies.
API regulations
? Create an API policy using Strapi Generators.
? Second-policy term for the policy
? Where would you like to see this policy added? Adding a policy to an already-existing API
? For what API is this intended? item
++/api/item/policies/second-policy.js ✔
✨ Completed in 22.58 seconds.
In the file src/api/item/policies/second-policy.js, you may locate your just generated policy.
This is the file’s appearance.
module.exports = (config, { strapi }, policyContext) => {
// Here, add your reasoning.
(“In second-policy policy.”); strapi.log.info;
const canDoSomething is set to true.
suppose (canDoSomething) {
return the truth;
~
return a false positive;
};
To make it easier to find, I’m also going to include another console.log in our policy.
(“In second-policy policy.”); strapi.log.info;
Setting up an API policy involves the same steps as setting up a global policy:
~
“admin::isAuthenticatedAdmin”: [Anonymous Function],
“admin::possessesPermissions”: {
the name ‘admin::hasPermissions’,
validator: [WrappedValidator function],
handler: [The handler’s function]
~,
If “admin::isTelemetryEnabled,” then {
calling it ‘admin::isTelemetryEnabled’,
validator: [WrappedValidator function],
handler: [The handler’s function]
~,
‘global::first-policy’: [Anonymous Function],
‘api::item.second-policy’: [Anonymous Function]
‘plugin::content-manager.possesses-draft-and-publish’: [Anonymous Function],
‘content-manager.hasPermissions.plugin’: {
The plugin ‘plugin::content-manager.hasPermissions’
validator: [WrappedValidator function],
handler: [The handler’s function]
~
~
Nicely, api::item.second-policy, our second policy, is now visible to you.
The file./src/api/item/routes/item.js has been changed.
require(“@strapi/strapi”).factories; const {createCoreRouter }
createCoreRouter(“api::item.item”, module.exports) {
configuration: {
locate: {
regulations: [
/ refer to a legally registered policy
“global::first-policy” ,
“api::item.second-policy” ,
// direct the user to a registered policy with unique settings
// { config: {} }, name: “global::policy-name”,
// directly pass the policy function
// (config, { strapi }, policyContext) => {
// give a true response;
// },
],
~,
~,
});
To check if we are receiving the console log message from our second policy, let’s do another GET request to http://localhost:1337/api/items.
Information from [2023-09-06 12:55:43.107] is in the first policy.
International Policy #################
[2023-09-06 12:55:43.108] details: Within the second policy.
200 [2023-09-06 12:55:43.111] http: GET /API/items (19 ms)
When a route is covered by an API policy, it is referenced using the policy-name. Use api::api-name.policy-name to refer to policies that are registered in a different API.
Make a file called.src/api/[api-name]/policies/[policy-name].js if you want to manually define a policy. To begin, you can optionally paste the following boilerplate into the file:
“use strict” ;
module.exports = (config, { strapi }, policyContext) => {
// Here, add your reasoning.
“In the policy.” – strapi.log.info;
const canDoSomething is set to true.
suppose (canDoSomething) {
return the truth;
~
return a false positive;
};
Moreover, policies may be scoped to plugins. Plugin policies are the name given to these kinds of policies. The plugin isAuthenticated from Users & Permissions is an illustration of a plugin policy. Any user submitting a request via a route that employs the authenticated policy must be authenticated for the request to be fulfilled.
Make a file called./src/plugins/[plugin-name]/policies/to manually establish a policy. You can start by optionally pasting this boilerplate:
“use strict” ;
module.exports = (config, { strapi }, policyContext) => {
// Here, add your reasoning.
“In the policy.” – strapi.log.info;
const canDoSomething is set to true.
suppose (canDoSomething) {
return the truth;
~
return a false positive;
};
Setting up in routes
Setting up a plugin policy is comparable to setting up global and API policies:
./src/api/[api-name]/routes/router.js should be opened.
In createCoreRouter, construct an object.
Include the policy in the array of policies.
require(“@strapi/strapi”).factories; const {createCoreRouter }
createCoreRouter(“api::restaurant.restaurant”, module.exports) {
configuration: {
locate: {
regulations: [
/ refer to a legally registered policy
“plugin::plugin-name.policy-name” ,
// direct the user to a registered policy with unique settings
{ config: {} }, name: “plugin::plugin-name.policy-name”,
// directly pass the policy function
(config, { strapi}, policyContext) => {
return the truth;
~,
],
~,
~,
});
Use plugin::plugin-name.policy-name to refer to a plugin policy.
Although this is outside the purview of this guide, you may also add plugin policies to API routes inside your plugin. Considering that an API endpoint-created plugin would be required.
In certain situations, receiving a request error alone is insufficient when a policy fails. Some of you may be curious as to why the policy didn’t work.
A route with multiple policies linked to it serves as an example. Because every policy failure responds by default in the same way, it will be challenging to track down the failure.
Policies that fail under multiple conditions provide another illustration. It is difficult to determine which circumstance caused the policy to fail in the absence of a thorough error notice.
A policy can be set up to return messages if it fails. This is how you may complete the straightforward process:
Add the PolicyError class to the policy file by importing it:
require(“@strapi/utils”) const utils;
const = utils.errors; PolicyError
Toss a PolicyError object containing the error’s information and message:
If (error) {
throw new PolicyError(details, message, and error);
Otherwise, {
return the truth;
~
Assume you are developing a store’s backend application. Right now, you’re developing an API that allows you to add, retrieve, and edit backend items. The backend needs the item’s name, code, and price to create it.
You can develop the project and policy by following these steps. Create a new Strapi project, then adhere to the instructions that follow.
With our item collecting type, we will utilize the Strapi app that we now have.
Construct the policy.
This project’s policy will ensure that any data supplied to the item’s created route adheres to a set format. A schema will be used to explain the format.
In case you are unaware, a schema is a description of the ideal structure for data.
We will use the Joi JavaScript library to build the schema. You can read this API reference if you’re not familiar with how Joi operates. Open the root folder of the project in your terminal, then type either of the following commands to install Joi:
# yarn
$ yarn + joi
# npm
$ npm install joi
You can now go to work on the policy.
First, go to src/api/item/policies and create a new API policy. The file can be called valid-input.js.
Now, insert the following code into the valid-input.js file located at./src/api/item/policies:
“use strict” ;
require(“joi”); const Joi =
require(“@strapi/utils”) const utils;
const = utils.errors; PolicyError
/**
* Policy for `valid input}
*/
module.exports = (config, { strapi }, policyContext) => {
// Obtain request body information
var requestData = body[“data”] in policyContext.request;
// Construct a schema for requesting body data validation.
Joi.object({) const schema =
Joi.string().required() is the name.
Joi.string() is the code.
[a-zA-Z0-9]{4}-.pattern(/^){3}[a-zA-Z0-9]{4}$/) // The format of the test is as follows: (four groups of alphanumeric characters, divided by hyphens)
.required(),
cost is Joi.number().necessary(),
});
// Verify the data in the request body.
const { error} = requestData.validate();
If (error) {
throw new PolicyError(error.details, “Invalid input data”);
Otherwise, {
// If the request body data is valid, allow the request to proceed.
return the truth;
~
};
To register the policy, take the following actions:
produce: {
[“api::item.valid-input”] policies
~
configuration: {
produce: {
[“api::item.valid-input”] policies
~,
locate: {
regulations: [
/ refer to a legally registered policy
“global::first-policy” ,
“api::item.second-policy” ,
// direct the user to a registered policy with unique settings
// { name: “global::policy-name”, config: {} }
// directly pass the policy function
// (config, { strapi }, policyContext) => {
// give a true response;
// },
],
~,
~,
});
~
“data”: void,
“Error”: {
“status”: 403,
“name” : “PolicyError” ,
“message” : “Invalid input data” ,
“specifics”: [
~
“message”: “\”name\” is not allowed to be empty”,
“path”: [“name”],
“type” : “string.empty” ,
“Context”: {
“label” : “name” ,
“value”: “,”
“key” : “name”
~
~
[
~
~
Now let’s submit a request with all fields completed.
~
“data”: {
“name” : “test” ,
“code” : “12e3-4r3d-35te-345a” ,
“price” : “9.99”
~
~
We now return a 200 status code and our item is generated after we pass valid data.
Good. Our strategy is effective. Fantastic work.
A strong foundation for customizing application logic, authorization, and authentication is offered by Strapi’s policies and customizations. With a highly configurable and secure backend, you can ensure efficiency and flexibility in your development projects.
If you’re looking for a Strapi development business to help you create an application using Strapi, another company you should look into is Appic Softwares. Through a range of projects, our talented team of Strapi developers has helped clients all over the world create Strapi apps.
Why then are you hesitant?
We are all ears!
5 Cowboys Way, Suite 300, Frisco, TX 75034, USA

Magdalenenstraße 34, 80638 München, Germany
© 2026 Appic Softwares. All Rights Reserved. |Privacy Policy