PageSourceSearch

https://sequelize.org/assets/js/d75cee2e.cb665665.js

js sequelize.org collected 2026-09-24 08:29:47 UTC 15,595 bytes, 1 lines download raw bytes

1"use strict";(globalThis.webpackChunk=globalThis.webpackChunk||[]).push([[8337],{48521(e,t,n){n.r(t),n.d(t,{assets:()=>o,contentTitle:()=>r,default:()=>h,frontMatter:()=>l,metadata:()=>a,toc:()=>d});const a=JSON.parse('{"id":"models/validations-and-constraints","title":"Validations & Constraints","description":"Validations are checks performed by Sequelize, in pure JavaScript.","source":"@site/docs/models/validations-and-constraints.md","sourceDirName":"models","slug":"/models/validations-and-constraints","permalink":"/docs/v7/models/validations-and-constraints","draft":false,"unlisted":false,"editUrl":"https://github.com/sequelize/website/tree/main/docs/models/validations-and-constraints.md","tags":[],"version":"current","lastUpdatedBy":"renovate[bot]","lastUpdatedAt":1775795365000,"sidebarPosition":6,"frontMatter":{"sidebar_position":6,"title":"Validations & Constraints"},"sidebar":"tutorialSidebar","previous":{"title":"Getters, Setters & Virtuals","permalink":"/docs/v7/models/getters-setters-virtuals"},"next":{"title":"Indexes & Uniques","permalink":"/docs/v7/models/indexes"}}');var i=n(74848),s=n(28453);const l={sidebar_position:6,title:"Validations & Constraints"},r=void 0,o={},d=[{value:"Not Null Constraints",id:"not-null-constraints",level:2},{value:"Unique Constraints",id:"unique-constraints",level:2},{value:"Foreign Key Constraints",id:"foreign-key-constraints",level:2},{value:"Check Constraints",id:"check-constraints",level:2},{value:"Validators",id:"validators",level:2},{value:"Attribute validators",id:"attribute-validators",level:3},{value:"<code>@sequelize/validator.js</code>",id:"sequelizevalidatorjs",level:3},{value:"Model validators",id:"model-validators",level:3},{value:"Asynchronous validators",id:"asynchronous-validators",level:3},{value:"Validation of nullable attributes",id:"validation-of-nullable-attributes",level:3}];function c(e){const t={a:"a",admonition:"admonition",br:"br",code:"code",em:"em",h2:"h2",h3:"h3",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,s.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsxs)(t.p,{children:[(0,i.jsx)(t.a,{href:"#validators",children:(0,i.jsx)(t.strong,{children:"Validations"})})," are checks performed by Sequelize, ",(0,i.jsx)(t.strong,{children:"in pure JavaScript"}),".",(0,i.jsx)(t.br,{}),"\n","They can be arbitrarily complex if you provide a custom validator function,\nor can be one of the ",(0,i.jsx)(t.a,{href:"#attribute-validators",children:"built-in validators"})," offered by Sequelize.",(0,i.jsx)(t.br,{}),"\n","If validation fails, no SQL query will be sent to the database at all."]}),"\n",(0,i.jsxs)(t.p,{children:[(0,i.jsx)(t.strong,{children:"Constraints"})," are rules defined ",(0,i.jsx)(t.strong,{children:"at the SQL level"})," and are enforced by the Database.",(0,i.jsx)(t.br,{}),"\n","Common examples are ",(0,i.jsx)(t.code,{children:"UNIQUE"}),". ",(0,i.jsx)(t.code,{children:"NOT NULL"})," and foreign key constraints."]}),"\n",(0,i.jsx)(t.h2,{id:"not-null-constraints",children:"Not Null Constraints"}),"\n",(0,i.jsxs)(t.p,{children:["We already talked about Not Null Constraints in the ",(0,i.jsx)(t.a,{href:"/docs/v7/models/defining-models#nullability",children:"section about Defining Models"}),".\nUsing the ",(0,i.jsx)(t.a,{href:"pathname:///api/v7/functions/_sequelize_core.decorators_legacy.NotNull.html",children:(0,i.jsx)(t.code,{children:"@NotNull"})})," decorator, you can define a Not Null Constraint on a column."]}),"\n",(0,i.jsx)(t.p,{children:"Sequelize also automatically adds a Not Null Validator to the attribute, meaning the Sequelize will also validate that the attribute is not null\nbefore sending the query to the database."}),"\n",(0,i.jsxs)(t.p,{children:["If an attempt is made to set ",(0,i.jsx)(t.code,{children:"null"})," to an attribute that does not allow null, a ",(0,i.jsx)(t.a,{href:"pathname:///api/v7/classes/_sequelize_core.index.ValidationError.html",children:(0,i.jsx)(t.code,{children:"ValidationError"})})," will be thrown ",(0,i.jsx)(t.em,{children:"without any SQL query being performed"}),"."]}),"\n",(0,i.jsx)(t.h2,{id:"unique-constraints",children:"Unique Constraints"}),"\n",(0,i.jsxs)(t.p,{children:["Unique constraints are created as unique indexes in the database. Read more about them in the ",(0,i.jsx)(t.a,{href:"/docs/v7/models/indexes#unique-indexes",children:"documentation on Indexe
1s"}),"."]}),"\n",(0,i.jsx)(t.h2,{id:"foreign-key-constraints",children:"Foreign Key Constraints"}),"\n",(0,i.jsx)(t.p,{children:"There are two ways of defining foreign key constraints in Sequelize:"}),"\n",(0,i.jsxs)(t.ul,{children:["\n",(0,i.jsxs)(t.li,{children:["By ",(0,i.jsx)(t.a,{href:"/docs/v7/associations/basics",children:"defining an association"})," between two models (",(0,i.jsx)(t.strong,{children:"recommended"}),")."]}),"\n",(0,i.jsxs)(t.li,{children:["Using the ",(0,i.jsx)(t.a,{href:"pathname:///api/v7/interfaces/_sequelize_core.index.ForeignKeyOptions.html#references",children:(0,i.jsx)(t.code,{children:"references"})})," option of the ",(0,i.jsx)(t.a,{href:"pathname:///api/v7/functions/_sequelize_core.decorators_legacy.Attribute.html",children:(0,i.jsx)(t.code,{children:"@Attribute"})})," decorator."]}),"\n"]}),"\n",(0,i.jsx)(t.h2,{id:"check-constraints",children:"Check Constraints"}),"\n",(0,i.jsxs)(t.admonition,{type:"note",children:[(0,i.jsxs)(t.p,{children:["Sequelize does not provide any way to declare Check Constraints on tables yet, but you can use the low-level ",(0,i.jsx)(t.a,{href:"pathname:///api/v7/classes/_sequelize_core.index.AbstractQueryInterface.html#addConstraint",children:(0,i.jsx)(t.code,{children:"QueryInterface#addConstraint"})})," API to add one yourself."]}),(0,i.jsxs)(t.p,{children:["We plan on adding a way to easily declare check constraints on models. See ",(0,i.jsx)(t.a,{href:"https://github.com/sequelize/sequelize/issues/11211",children:"issue #11211"}),"."]})]}),"\n",(0,i.jsxs)(t.p,{children:["This example showcases how to add a check constraint after a table has been created though ",(0,i.jsx)(t.a,{href:"/docs/v7/models/model-synchronization",children:(0,i.jsx)(t.code,{children:"sync"})}),":"]}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-ts",children:"import { Sequelize, Model, InferAttributes, InferCreationAttributes } from '@sequelize/core';\nimport { NotNull, Attribute, AfterSync } from '@sequelize/core/decorators-legacy';\nimport { SqliteDialect } from '@sequelize/sqlite3';\n\nclass User extends Model<InferAttributes<User>, InferCreationAttributes<User>> {\n  @Attribute(DataTypes.STRING)\n  @NotNull\n  declare email: string;\n\n  @AfterSync\n  static async onSync() {\n    // highlight-next-line\n    await this.sequelize.queryInterface.addConstraint(this.table, {\n      fields: ['email'],\n      type: 'check',\n      where: {\n        email: {\n          [Op.like]: '%@sequelizejs.com',\n        },\n      },\n    });\n  }\n}\n\nconst sequelize = new Sequelize({\n  dialect: SqliteDialect,\n  models: [User],\n});\n\nawait sequelize.sync();\n"})}),"\n",(0,i.jsx)(t.admonition,{type:"caution",children:(0,i.jsxs)(t.p,{children:["We do not recommend using ",(0,i.jsx)(t.code,{children:"sync"})," in production, as it can lead to data loss. See ",(0,i.jsx)(t.a,{href:"/docs/v7/models/model-synchronization",children:"Model Synchronization"})," for more information."]})}),"\n",(0,i.jsx)(t.h2,{id:"validators",children:"Validators"}),"\n",(0,i.jsxs)(t.p,{children:["Validators are JavaScript functions that are run before an instance is persisted or updated in the database.\nYou can also run validators manually using ",(0,i.jsx)(t.a,{href:"pathname:///api/v7/classes/_sequelize_core.index.Model.html#validate",children:(0,i.jsx)(t.code,{children:"Model#validate"})}),"."]}),"\n",(0,i.jsx)(t.h3,{id:"attribute-validators",children:"Attribute validators"}),"\n",(0,i.jsx)(t.p,{children:"Attribute validators are used to validate the value of a single attribute.\nSequelize provides a number of built-in validators, through extra packages, but you can also define your own."}),"\n",(0,i.jsxs)(t.p,{children:["Sequelize provides the ",(0,i.jsx)(t.a,{href:"pathname:///api/v7/functions/_sequelize_core.decorators_legacy.ValidateAttribute.html",children:(0,i.jsx)(t.code,{children:"@ValidateAttribute"})})," decorator to define custom validators."]}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-ts",children:"import { Model, DataTypes } from '@sequelize/core';\nimport { Attribute, NotNull, ValidateAttribute } from '@sequelize/core/decorators-legacy';\n\nclass User extends Model {\n  @Attribute(DataTypes.STRING)\n  @NotNull\
1n  // highlight-start\n  @ValidateAttribute((value: unknown, user: User, attributeName: string) => {\n    // this function will run when this attribute is validated.\n    if (name.length === 0) {\n      throw new Error('Name cannot be empty');\n    }\n  })\n  // highlight-end\n  declare name: string;\n}\n"})}),"\n",(0,i.jsx)(t.h3,{id:"sequelizevalidatorjs",children:(0,i.jsx)(t.code,{children:"@sequelize/validator.js"})}),"\n",(0,i.jsxs)(t.p,{children:["The ",(0,i.jsx)(t.a,{href:"https://www.npmjs.com/package/@sequelize/validator.js",children:(0,i.jsx)(t.code,{children:"@sequelize/validator.js"})})," package provides a number validators\nbased on the ",(0,i.jsx)(t.a,{href:"https://www.npmjs.com/package/validator",children:(0,i.jsx)(t.code,{children:"validator.js"})})," package, such as email validation and regex matching."]}),"\n",(0,i.jsx)(t.p,{children:(0,i.jsx)(t.strong,{children:"\u26a0\ufe0f As indicated in the validator.js documentation, the library validates and sanitizes strings only."})}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-ts",children:"import { Model, DataTypes } from '@sequelize/core';\nimport { Attribute, NotNull } from '@sequelize/core/decorators-legacy';\nimport { IsEmail } from '@sequelize/validator.js';\n\nclass User extends Model {\n  @Attribute(DataTypes.STRING)\n  @NotNull\n  // highlight-next-line\n  @IsEmail\n  declare email: string;\n}\n"})}),"\n",(0,i.jsxs)(t.p,{children:["Head to ",(0,i.jsx)(t.a,{href:"pathname:///api/v7/modules/_sequelize_validator_js.html",children:"its TypeDoc page"})," for the list of available validators."]}),"\n",(0,i.jsx)(t.admonition,{title:"Future development",type:"note",children:(0,i.jsxs)(t.p,{children:["We're working on adding support for more validation libraries, see ",(0,i.jsx)(t.a,{href:"https://github.com/sequelize/sequelize/issues/15497",children:"issue #15497"}),"."]})}),"\n",(0,i.jsx)(t.h3,{id:"model-validators",children:"Model validators"}),"\n",(0,i.jsx)(t.p,{children:"You can also define validators that run on the whole model, rather than on a single attribute."}),"\n",(0,i.jsx)(t.p,{children:"Model validator methods are called with the model object's context and are deemed to fail if they throw an error, otherwise pass.\nThis is just the same as with custom attribute-specific validators."}),"\n",(0,i.jsxs)(t.p,{children:["For example, you could ensure that either ",(0,i.jsx)(t.code,{children:"latitude"})," and ",(0,i.jsx)(t.code,{children:"longitude"})," are both set, or neither are."]}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-ts",children:"class Place extends Model {\n  @Attribute(DataTypes.INTEGER)\n  declare latitude: number | null;\n\n  @Attribute(DataTypes.INTEGER)\n  declare longitude: number | null;\n\n  // highlight-start\n  @ModelValidator\n  validateCoords() {\n    if ((this.latitude === null) !== (this.longitude === null)) {\n      throw new Error('Either both latitude and longitude, or neither!');\n    }\n  }\n  // highlight-end\n}\n"})}),"\n",(0,i.jsx)(t.p,{children:"If you need to validate an attribute based on the value of another attribute, we highly recommend using Model Validators instead of Attribute Validators,\nbecause Model Validators are always run, while Attribute Validators are only run if the attribute's value has changed."}),"\n",(0,i.jsx)(t.p,{children:"Model validator functions can also be static, in which case they will receive the instance to validate as the first argument:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-ts",children:"class Place extends Model {\n  @Attribute(DataTypes.INTEGER)\n  declare latitude: number | null;\n\n  @Attribute(DataTypes.INTEGER)\n  declare longitude: number | null;\n\n  // highlight-start\n  @ModelValidator\n  static validateCoords(place: Place) {\n    if ((place.latitude === null) !== (place.longitude === null)) {\n      throw new Error('Either both latitude and longitude, or neither!');\n    }\n  }\n  // highlight-end\n}\n"})}),"\n",(0,i.jsxs)(t.admonition,{type:"caution",children:[(0,i.jsx)(t.p,{children:"As stated above, model validators are always run."}),(0,i.jsxs)(t.p,{children:["If you did not load every attribute of a model, and you have a model validator that depends on an attribute that was not loaded,\nit will still run but the attribute will be ",(0,i.jsx)(t.code,{children:"undefined"}),". Make sure your model validator can handle this case (for instance, by stopping validation if the attribute is ",(0,i.jsx)(t.code,{children:"undefined"}),")."]})]}),"\n",(0,i.jsx)(t.h3,{id:"asynchronous-validators",children:"Asynchronous validators"}),"\n",(0,i.jsx)(t.p,{children:"Both attribute and model validators can be asynchronous. To do so, simply return a promise from the validator function."}),"\n",(0,i.jsxs)(t.p,{children:["This makes it possible to, for instance, load data from the database to validate the model. Be aware that ",(0,i.jsx)(t.em,{children:"this can have serious impacts on your application's performance"}),"."]}),"\n",(0,i.jsx)(t.h3,{id:"validation-of-nullable-attributes",children:"Validation of nullable attributes"}),"\n",(0,i.jsxs)(t.p,{children:["The nullability validation takes precedence over the attribute val
1idation. If the value of an attribute is null, its ",(0,i.jsx)(t.a,{href:"#attribute-validators",children:(0,i.jsx)(t.strong,{children:"attribute validators"})})," are not executed.\nOnly its nullability validation is run."]}),"\n",(0,i.jsxs)(t.p,{children:["On the other hand, ",(0,i.jsx)(t.a,{href:"#model-validators",children:(0,i.jsx)(t.strong,{children:"model validators"})})," are always executed, even if the value of an attribute is null.\nThis means that you can use model validators to implement custom nullability validation:"]}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-ts",children:"import { Model, DataTypes } from '@sequelize/core';\nimport { Attribute, NotNull } from '@sequelize/core/decorators-legacy';\nimport { IsEmail } from '@sequelize/validator.js';\n\nclass User extends Model {\n  @Attribute(DataTypes.STRING)\n  declare name: string | null;\n\n  @Attribute(DataTypes.INTEGER)\n  declare age: number;\n\n  // highlight-start\n  @ModelValidator\n  onValidate() {\n    if (this.name === null && this.age !== 10) {\n      throw new Error(\"name can't be null unless age is 10\");\n    }\n  }\n  // highlight-end\n}\n"})})]})}function h(e={}){const{wrapper:t}={...(0,s.R)(),...e.components};return t?(0,i.jsx)(t,{...e,children:(0,i.jsx)(c,{...e})}):c(e)}},28453(e,t,n){n.d(t,{R:()=>l,x:()=>r});var a=n(96540);const i={},s=a.createContext(i);function l(e){const t=a.useContext(s);return a.useMemo(function(){return"function"==typeof e?e(t):{...t,...e}},[t,e])}function r(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:l(e.components),a.createElement(s.Provider,{value:t},e.children)}}}]);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.