Skip to main content
Version: v7 - alpha

Defining a Model

In this tutorial you will learn what models are in Sequelize and how to use them.

Concept

Models are the essence of Sequelize. A model is an abstraction that represents a table in your database. In Sequelize, it is a class that extends the Model class.

The model tells Sequelize several things about the entity it represents, such as the name of the table in the database and which columns it has (and their data types).

A model in Sequelize has a name. This name does not have to be the same name of the table it represents in the database. Usually, models have singular names (such as User) while tables have pluralized names (such as users), although this is fully configurable.

Each instance of a model maps to one row of the table in the database. Basically, model instances are DAOs.

Defining a Model

This chapter will go into detail about how to create a model in Sequelize. Sequelize uses a class-based approach to define models, and makes heavy uses of decorators to define the model's metadata. You can choose to avoid using decorators, but you should read this chapter first.

info

Sequelize currently only supports the legacy/experimental decorator format. Support for the new decorator format will be added in a future release.

All decorators must be imported from @sequelize/core/decorators-legacy:

import { Attribute, Table } from '@sequelize/core/decorators-legacy';

Using legacy decorators requires to use a transpiler such as TypeScript, Babel or others to compile them to JavaScript. Alternatively, Sequelize also supports a legacy approach that does not require using decorators, but this is discouraged.

If you're using TypeScript, you will also need to configure it to be able to resolve this export, see our Getting Started guide for more information.

To learn with an example, we will consider that we want to create a model to represent users, which have a firstName and a lastName. We want our model to be called User, and the table it represents is called users in the database.

Defining a model is simple: Create a class that extends the Model class and add instance properties to it.

import {
Sequelize,
DataTypes,
Model,
InferAttributes,
InferCreationAttributes,
CreationOptional,
} from '@sequelize/core';
import { Attribute, PrimaryKey, AutoIncrement, NotNull } from '@sequelize/core/decorators-legacy';
import { SqliteDialect } from '@sequelize/sqlite3';

const sequelize = new Sequelize({ dialect: SqliteDialect });

export class User extends Model<InferAttributes<User>, InferCreationAttributes<User>> {
@Attribute(DataTypes.INTEGER)
@PrimaryKey
@AutoIncrement
declare id: CreationOptional<number>;

@Attribute(DataTypes.STRING)
@NotNull
declare firstName: string;

@Attribute(DataTypes.STRING)
declare lastName: string | null;
}

Many decorators are available to configure your attributes. You can find the list of decorators here. You can also define associations between models, which will be covered in a following chapter.

Initializing the Model

After defining the model, you need to initialize it. This is done by passing it to the Sequelize constructor:

import { Sequelize } from '@sequelize/core';
import { SqliteDialect } from '@sequelize/sqlite3';
import { User } from './models/user.model.js';

export const sequelize = new Sequelize({
dialect: SqliteDialect,
// add all your models here
models: [User],
});

You can also load all your models dynamically by using importModels. Note that this method is async, and uses import (esm), not require (commonjs):

import { Sequelize, importModels } from '@sequelize/core';
import { SqliteDialect } from '@sequelize/sqlite3';
import { fileURLToPath } from 'node:url';
import { dirname } from 'node:path';

const __dirname = dirname(fileURLToPath(import.meta.url));

export const sequelize = new Sequelize({
dialect: SqliteDialect,
// this will load all model classes found in files matching this glob pattern.
models: await importModels(__dirname + '/**/*.model.{ts,js}'),
});

importModels uses fast-glob, and expects a glob pattern (or an array of glob patterns) as its first argument.

Without Decorators

If you're working on a project that was created before Sequelize 7, you're likely using the old way of defining models. This is still supported, but we recommend to use the new way of defining models.

If you do not want to use decorators, you can continue to use the old way of defining models. Head to our page about Legacy Model Definitions to learn more about the old API.

Column Data Types

Every attribute you define in your model must have a data type. You can use the @Attribute decorator to define the data type of an attribute:

The data type defines the type of your column. e.g. an attribute with a type DataTypes.INTEGER will result in a column of type INTEGER.

The list of supported Data Types is available here.

Nullability

Just like in SQL, attributes are nullable by default in Sequelize

You can change this behavior by using the @NotNull decorator:

import { DataTypes, Model, InferAttributes, InferCreationAttributes } from '@sequelize/core';
import { Attribute, NotNull } from '@sequelize/core/decorators-legacy';

class User extends Model<InferAttributes<User>, InferCreationAttributes<User>> {
@Attribute(DataTypes.STRING)
@NotNull
declare firstName: string;

@Attribute(DataTypes.STRING)
declare lastName: string | null;
}

Default Values

By default, Sequelize assumes that the default value of a column is null. This behavior can be changed by using the @Default decorator:

import {
DataTypes,
Model,
InferAttributes,
InferCreationAttributes,
CreationOptional,
} from '@sequelize/core';
import { Attribute, NotNull, Default } from '@sequelize/core/decorators-legacy';

class User extends Model<InferAttributes<User>, InferCreationAttributes<User>> {
@Attribute(DataTypes.STRING)
@NotNull
@Default('John')
declare firstName: CreationOptional<string>;
}
CreationOptional

If you use @Default, your attribute won't need to be specified when calling methods such as User.create. To let TypeScript know that this attribute has a default value, you can use the CreationOptional type, like in the example above.

Dynamic JS default values

Instead of a static value, you can also use a JavaScript function that sequelize will call every time a new instance is created. Sequelize provides the built-in DataTypes.NOW for the current timestamp, but a custom function can be used as well:

import uniqid from 'uniqid';
import {
DataTypes,
Model,
InferAttributes,
InferCreationAttributes,
CreationOptional,
} from '@sequelize/core';
import { Attribute, NotNull, Default, PrimaryKey } from '@sequelize/core/decorators-legacy';

class User extends Model<InferAttributes<User>, InferCreationAttributes<User>> {
@PrimaryKey
@Attribute(DataTypes.STRING(18))
// Generate a new ID every time a new instance is created
@Default(() => uniqid())
declare id: CreationOptional<string>;

@Attribute(DataTypes.DATE)
@NotNull
// The current date/time will be used to populate this column at the moment of insertion
@Default(DataTypes.NOW)
declare registeredAt: CreationOptional<Date>;
}
caution

The generation of values for DataTypes.NOW and other JavaScript functions are not handled by the Database, but by Sequelize itself. This means that they will only be used when using Model methods. They will not be used in raw queries, in migrations, and all other places where Sequelize does not have access to the Model.

Read about SQL based alternatives in Dynamic SQL default values.

Dynamic SQL default values

You can also use a SQL function as a default value using raw SQL. This has the advantage over dynamic JS default values that the function will always be called, since it is handled by the database, not by Sequelize.

For instance, you could use the sql.fn function to make the database generate a random number for you:

import {
DataTypes,
Model,
sql,
InferAttributes,
InferCreationAttributes,
CreationOptional,
} from '@sequelize/core';
import { Attribute, Default } from '@sequelize/core/decorators-legacy';

class User extends Model<InferAttributes<User>, InferCreationAttributes<User>> {
@Attribute(DataTypes.FLOAT)
@Default(sql.fn('random'))
declare randomNumber: CreationOptional<number>;
}

Sequelize also provides 2 built-in functions, sql.uuidV1 and sql.uuidV4, that will generate a UUID in SQL if possible, and fallback to a JavaScript implementation otherwise.

Primary Keys

Sequelize automatically adds an auto-incremented integer attribute called id as primary key if none is specified.

If you use TypeScript, you can declare the typing of this attribute like this:

import {
DataTypes,
Model,
InferAttributes,
InferCreationAttributes,
CreationOptional,
} from '@sequelize/core';

class User extends Model<InferAttributes<User>, InferCreationAttributes<User>> {
declare id: CreationOptional<number>;
}

If you want to use a different attribute, type, or want to use a composite primary key, you can use the @PrimaryKey decorator. This will stop Sequelize from adding the id attribute automatically:

import {
DataTypes,
Model,
InferAttributes,
InferCreationAttributes,
CreationOptional,
} from '@sequelize/core';
import { Attribute, PrimaryKey, AutoIncrement } from '@sequelize/core/decorators-legacy';

class User extends Model<InferAttributes<User>, InferCreationAttributes<User>> {
@Attribute(DataTypes.INTEGER)
@PrimaryKey
@AutoIncrement
declare internalId: CreationOptional<number>;
}
CreationOptional

If you use @AutoIncrement, your attribute won't need to be specified when calling methods such as User.create. To let TypeScript know that this attribute has a default value, you can use the CreationOptional type, like in the example above.

The @AutoIncrement decorator can also be used on primary key columns to make them auto-incremented.

You table cannot have a primary key? See How to remove the primary key.

Composite Primary Keys

Composite primary keys are supported by using the @PrimaryKey decorator on multiple attributes:

import { DataTypes, Model, InferAttributes, InferCreationAttributes } from '@sequelize/core';
import { Attribute, PrimaryKey } from '@sequelize/core/decorators-legacy';

class UserRole extends Model<InferAttributes<UserRole>, InferCreationAttributes<UserRole>> {
@Attribute(DataTypes.INTEGER)
@PrimaryKey
declare userId: number;

@Attribute(DataTypes.INTEGER)
@PrimaryKey
declare roleId: number;
}

Table & Column names

Head to the Naming Strategies API page to learn how to customize the names of your tables and columns.

Database schema

By default, Sequelize places your table in your database's default schema. You can specify a different schema by using the schema model option:

import { Model } from '@sequelize/core';
import { Table } from '@sequelize/core/decorators-legacy';

// This model's table will be created in the "public" schema
@Table({ schema: 'public' })
export class User extends Model {}

You can also change the default schema for all models by setting the schema option in the Sequelize constructor:

import { Model, Sequelize } from '@sequelize/core';
import { SqliteDialect } from '@sequelize/sqlite3';

class User extends Model {}

const sequelize = new Sequelize({
dialect: SqliteDialect,
// All models that don't specify a schema will be created in the "public" schema by default
schema: 'public',
models: [User],
});

Model Methods

Sequelize models are classes. You can very easily add custom instance or class level methods.

info

Model provides a suite of built-in static & instance methods that can be used to interact with the database.

Take a look at the API Reference for Model for more information

import { Model, InferCreationAttributes, InferAttributes } from '@sequelize/core';
import { SqliteDialect } from '@sequelize/sqlite3';
import { Attribute, NotNull } from '@sequelize/core/decorators-legacy';

class User extends Model<InferAttributes<User>, InferCreationAttributes<User>> {
@Attribute(DataTypes.STRING)
@NotNull
declare firstname: string;

@Attribute(DataTypes.STRING)
@NotNull
declare lastname: string;

instanceLevelMethod() {
return 'bar';
}

getFullname() {
return [this.firstname, this.lastname].join(' ');
}

static classLevelMethod() {
return 'foo';
}
}

const sequelize = new Sequelize({
dialect: SqliteDialect,
models: [User],
});

console.log(User.classLevelMethod()); // 'foo'
const user = User.build({ firstname: 'Jane', lastname: 'Doe' });
console.log(user.instanceLevelMethod()); // 'bar'
console.log(user.getFullname()); // 'Jane Doe'

Where to go from here?

A good next step is to synchronise your models with the database, after which you'll be able to create, read, update and delete your models.

Alternatively, find out how to define associations between models, learn about indexes, constraints, and other advanced features, or take a look at the API Reference of the @Attribute and @Table decorators to learn about the many more options they offer to customize your attributes and models.