# Models

As Strapi is a headless Content Management System (CMS), creating a data structure for the content is one of the most important aspects of using the software. Models define a representation of the data structure.

There are 2 different types of models in Strapi:

  • content-types, which can be collection types or single types, depending on how many entries they manage,
  • and components that are data structures re-usable in multiple content-types.

If you are just starting out, it is convenient to generate some models with the Content-type Builder directly in the admin panel. The user interface takes over a lot of validation tasks and showcases all the options available to create the content's data structure. The generated model mappings can then be reviewed at the code level using this documentation.

# Model creation

Content-types and components models are created and stored differently.

# Content-types

Content-types in Strapi can be created:

The content-types has the following models files:

  • schema.json for the model's schema definition. (generated automatically, when creating content-type with either method)
  • lifecycles.js for lifecycle hooks. This file must be created manually.

These models files are stored in ./src/api/[api-name]/content-types/[content-type-name]/, and any JavaScript or JSON file found in these folders will be loaded as a content-type's model (see project structure).

# Components

Component models can't be created with CLI tools. Use the Content-type Builder or create them manually.

Components models are stored in the ./src/components folder. Every component has to be inside a subfolder, named after the category the component belongs to (see project structure).

# Model schema

The schema.json file of a model consists of:

  • settings, such as the kind of content-type the model represents or the table name in which the data should be stored,
  • information, mostly used to display the model in the admin panel and access it through the REST and GraphQL APIs,
  • attributes, which describe the data structure of the model,
  • and options used to defined specific behaviors on the model.

# Model settings

General settings for the model can be configured with the following parameters:

Parameter Type Description
tableName String Database table name in which the data should be stored

only for content-types
String Defines if the content-type is:
  • a collection type (collectionType)
  • or a single type (singleType)
// ./api/[api-name]/content-types/restaurant/schema.json

  "kind": "collectionType",
  "tableName": "Restaurants_v1",

# Model information

The info key in the model's schema describes information used to display the model in the admin panel and access it through the Content API. It includes the following parameters:

Parameter Type Description
displayName String Default name to use in the admin panel
singularName String Singular form of the content-type name.
Used to generate the API routes and databases/tables collection.

Should be kebab-case.
pluralName String Plural form of the content-type name.
Used to generate the API routes and databases/tables collection.

Should be kebab-case.
description String Description of the model

only for Components
String FontAwesome (opens new window) (v5) icon name to use for the component's icon in the admin panel
// ./src/api/[api-name]/content-types/restaurant/schema.json

  "info": {
    "displayName": "Restaurant",
    "singularName": "restaurant",
    "pluralName": "restaurants",
    "description": ""

# Model attributes

The data structure of a model consists of a list of attributes. Each attribute has a type parameter, which describes its nature and defines the attribute as a simple piece of data or a more complex structure used by Strapi.

Many types of attributes are available:

  • scalar types (e.g. strings, dates, numbers, booleans, etc.),
  • Strapi-specific types, such as:

The type parameter of an attribute should be one of the following values:

Type categories Available types
String types
  • string
  • text
  • richtext
  • enumeration
  • email
  • password
  • uid
Date types
  • date
  • time
  • datetime
  • timestamp
Number types
  • integer
  • biginteger
  • float
  • decimal
Other generic types
  • boolean
  • array
  • json
Special types unique to Strapi
Internationalization (i18n)-related types

Can only be used if the i18n plugin is installed
  • locale
  • localizations

# Validations

Basic validations can be applied to attributes using the following parameters:

Parameter Type Description Default
required Boolean If true, adds a required validator for this property false
max Integer Checks if the value is greater than or equal to the given maximum -
min Integer Checks if the value is less than or equal to the given minimum -
minLength Integer Minimum number of characters for a field input value -
maxLength Integer Maximum number of characters for a field input value -
private Boolean If true, the attribute will be removed from the server response.

๐Ÿ’ก This is useful to hide sensitive data.
configurable Boolean If false, the attribute isn't configurable from the Content-type Builder plugin. true
// ./src/api/[api-name]/content-types/restaurant/schema.json

  // ...
  "attributes": {
    "title": {
      "type": "string",
      "minLength": 3,
      "maxLength": 99,
      "unique": true
    "description": {
      "default": "My description",
      "type": "text",
      "required": true
    "slug": {
      "type": "uid",
      "targetField": "title"
    // ...

# Database validations and settings

โœ‹ ๐Ÿšง This API is considered experimental.

These settings should be reserved to an advanced usage, as they might break some features. There are no plans to make these settings stable.

Database validations and settings are custom options passed directly onto the tableBuilder Knex.js function during schema migrations. Database validations allow for an advanced degree of control for setting custom column settings. The following options are set in a column: {} object per attribute:

Parameter Type Description Default
name string Changes the name of the column in the database -
defaultTo string Sets the database defaultTo, typically used with notNullable -
notNullable boolean Sets the database notNullable, ensures that columns cannot be null false
unsigned boolean Only applies to number columns, removes the ability to go negative but doubles maximum length false
unique boolean Enforces database level unique, caution when using with draft & publish feature false
type string Changes the database type, if type has arguments, you should pass them in args -
args array Arguments passed into the Knex.js function that changes things like type []
// ./src/api/[api-name]/content-types/restaurant/schema.json

  // ...
  "attributes": {
    "title": {
      "type": "string",
      "minLength": 3,
      "maxLength": 99,
      "unique": true,
      "column": {
        "unique": true // enforce database unique also
    "description": {
      "default": "My description",
      "type": "text",
      "required": true,
      "column": {
        "defaultTo": "My description", // set database level default
        "notNullable": true // enforce required at database level, even for drafts
    "rating": {
      "type": "decimal",
      "default": 0,
      "column": {
        "defaultTo": 0,
        "type": "decimal", // using the native decimal type but allowing for custom precision
        "args": [
          6,1 // using custom precision and scale
    // ...

# uid type

The uid type is used to automatically prefill the field value in the admin panel with a unique identifier (UID) (e.g. slugs for articles) based on 2 optional parameters:

  • targetField (string): If used, the value of the field defined as a target is used to auto-generate the UID.
  • options (string): If used, the UID is generated based on a set of options passed to the underlying uid generator (opens new window). The resulting uid must match the following regular expression pattern: /^[A-Za-z0-9-_.~]*$.

# Relations

Relations link content-types together. Relations are explicitly defined in the attributes of a model with type: 'relation' and accept the following additional parameters:

Parameter Description
relation The type of relation among these values:
  • oneToOne
  • oneToMany
  • manyToOne
  • manyToMany
target Accepts a string value as the name of the target content-type
mappedBy and inversedBy

In bidirectional relations, the owning side declares the inversedBy key while the inversed side declares the mappedBy key

# Components

Component fields create a relation between a content-type and a component structure. Components are explicitly defined in the attributes of a model with type: 'component' and accept the following additional parameters:

Parameter Type Description
repeatable Boolean Could be true or false depending on whether the component is repeatable or not
component String Define the corresponding component, following this format:
// ./src/api/[apiName]/restaurant/content-types/schema.json

  "attributes": {
    "openinghours": {
      "type": "component",
      "repeatable": true,
      "component": "restaurant.openinghours"

# Dynamic zones

Dynamic zones create a flexible space in which to compose content, based on a mixed list of components.

Dynamic zones are explicitly defined in the attributes of a model with type: 'dynamiczone'. They also accepts a components array, where each component should be named following this format: <category>.<componentName>.

// ./src/api/[api-name]/content-types/article/schema.json

  "attributes": {
    "body": {
      "type": "dynamiczone",
      "components": ["article.slider", "article.content"]

# Model options

The options key is used to define specific behaviors and accepts the following parameter:

Parameter Type Description
privateAttributes Array of strings Allows treating a set of attributes as private, even if they're not actually defined as attributes in the model. It could be used to remove them from API responses timestamps.

The set of privateAttributes defined in the model are merged with the privateAttributes defined in the global Strapi configuration.
draftAndPublish Boolean Enables the draft and publish feature.

Default value: false
// ./src/api/[api-name]/content-types/restaurant/schema.json

  "options": {
    "privateAttributes": ["id", "created_at"],
    "draftAndPublish": false

# Lifecycle hooks

Lifecycle hooks are functions that get triggered when Strapi queries are called. They are triggered automatically when managing content through the administration panel or when developing custom code using queriesยท

Lifecycle hooks can be customized declaratively or programmatically.


Lifecycles hooks are not triggered when using directly the knex (opens new window) library instead of Strapi functions.

# Available lifecycle events

The following lifecycle events are available:

  • beforeCreate
  • beforeCreateMany
  • afterCreate
  • afterCreateMany
  • beforeUpdate
  • beforeUpdateMany
  • afterUpdate
  • afterUpdateMany
  • beforeDelete
  • beforeDeleteMany
  • afterDelete
  • afterDeleteMany
  • beforeCount
  • afterCount
  • beforeFindOne
  • afterFindOne
  • beforeFindMany
  • afterFindMany

# Hook event object

Lifecycle hooks are functions that take an event parameter, an object with the following keys:

Key Type Description
action String Lifecycle event that has been triggered (see list)
model Object Model object
em EntityManagerObject EntityManager
params Object Accepts the following parameters:
  • data
  • select
  • where
  • orderBy
  • limit
  • offset
  • populate
result Object Optional, only available with afterXXX events

Contains the result of the action.
state Object Query state, can be used to share state between beforeXXX and afterXXX events of a query.

# Declarative and programmatic usage

To configure a content-type lifecycle hook, create a lifecycles.js file in the ./api/[api-name]/content-types/[content-type-name]/ folder.

Each event listener is called sequentially. They can be synchronous or asynchronous.

// ./src/api/[api-name]/content-types/restaurant/lifecycles.js

module.exports = {
  beforeCreate(event) {
    const { data, where, select, populate } = event.params;

    // let's do a 20% discount everytime
    event.params.data.price = event.params.data.price * 0.8;

  afterCreate(event) {
    const { result, params } = event;

    // do something to the result;

Using the database layer API, it's also possible to register a subscriber and listen to events programmatically:

// ./src/api/[api-name]/content-types/restaurant/lifecycles.js

// registering a subscriber
  models: [], // optional;

  beforeCreate(event) {
    const { data, where, select, populate } = event.params;

    event.state = 'doStuffAfterWards';

  afterCreate(event) {
    if (event.state === 'doStuffAfterWards') {

    const { result, params } = event;

    // do something to the result

// generic subscribe for generic handling
strapi.db.lifecycles.subscribe((event) => {
  if (event.action === 'beforeCreate') {
    // do something