DEV Community

Cover image for The Comprehensive Sequelize Cheatsheet
Aniket
Aniket

Posted on • Edited on

The Comprehensive Sequelize Cheatsheet

Sequelize is the most famous Node ORM and is quite feature-rich, but while using it I spend much of my time juggling around between the documentation and different google searches.
This Cheatsheet is the one that I always wanted but was never able to find.
See any error or anything missing? Comment below, or better, send a pull request to the repo linked in the end.

Table of Contents

  1. Installing Dependencies
    1. Installing Sequelize
    2. Installing Database Driver
  2. Setting up a Connection
    1. Instance Creation
    2. Testing Connection
    3. Closing Connection
  3. Defining Models
    1. Basic Definition
    2. Extending Column Definition
      1. Basic Extentions
      2. Composite Unique Key
      3. Getters and Setters
      4. Validations
        1. Per Attribute Validations
        2. Model Wide Validations
      5. Timestamps
      6. Database Synchronization
      7. Expansion of Models
      8. Indexes
  4. Associations
    1. Defining Associations
      1. hasOne
      2. belongsTo
      3. hasMany
      4. belongsToMany
    2. Relations
      1. One to One
      2. One to Many
      3. Many to Many
  5. Instances
    1. Creating Instances
      1. build
      2. create
    2. Mutating Instances
      1. Update
      2. Delete
  6. Using Models
    1. Methods
      1. findByPk
      2. findOne
      3. findOrCreate
      4. findAll
      5. findAndCountAll
      6. count
      7. max
      8. min
      9. sum
    2. Filtering
      1. where
        1. Operators
      2. order
      3. Pagination and Limiting
  7. Things I did not include in this Cheatsheet (with links to official docs)
    1. Hooks
    2. Transactions
    3. Scopes
    4. Raw Queries
    5. Eager Loading

Installing Dependencies

Installing Sequelize



npm install --save sequelize


Enter fullscreen mode Exit fullscreen mode

Installing Database Driver

You also need to install the driver for the database you're using.



# One of the following:
npm install --save pg pg-hstore # Postgres If node version < 14 use pg@7.12.1 instead
npm install --save mysql2
npm install --save mariadb
npm install --save sqlite3
npm install --save tedious # Microsoft SQL Server


Enter fullscreen mode Exit fullscreen mode

Setting up a Connection

A Sequelize instance must be created to connect to the database. By default, this connection is kept open and used for all the queries but can be closed explicitly.

Instance Creation



const Sequelize = require('sequelize');

// Option 1: Passing parameters separately
const sequelize = new Sequelize('database', 'username', 'password', {
  host: 'localhost',
  dialect: /* one of 'mysql' | 'mariadb' | 'postgres' | 'mssql' */
});

// Option 2: Passing a connection URI
const sequelize = new Sequelize('postgres://user:pass@example.com:5432/dbname');

// For SQLite, use this instead
const sequelize = new Sequelize({
  dialect: 'sqlite',
  storage: 'path/to/database.sqlite'
});


Enter fullscreen mode Exit fullscreen mode

For more detailed information about connecting to different dialects, check out the official docs

Testing Connection

.authenticate() can be used with the created instance to check whether the connection is working.



sequelize
  .authenticate()
  .then(() => {
    console.log("Connection has been established successfully.");
  })
  .catch((err) => {
    console.error("Unable to connect to the database:", err);
  });


Enter fullscreen mode Exit fullscreen mode

Closing Connection



sequelize.close();


Enter fullscreen mode Exit fullscreen mode

Defining Models

Basic Definition

To define mappings between Model and Table, we can use the .define() method
To set up a basic model with only attributes and their datatypes



const ModelName = sequelize.define("tablename", {
  // s will be appended automatically to the tablename
  firstColumn: Sequelize.INTEGER,
  secondColumn: Sequelize.STRING,
});


Enter fullscreen mode Exit fullscreen mode

For getting a list of all the data types supported by Sequelize, check out the official docs

Extending Column Definition

Basic Extentions

Apart from datatypes, many other options can also be set on each column



const ModelName = sequelize.define("tablename", {
  firstColumn: {
    // REQUIRED
    type: Sequelize.INTEGER,
    // OPTIONAL
    allowNull: false, // true by default
    defaultValue: 1,
    primaryKey: true, // false by default
    autoIncrement: true, // false by default
    unique: true,
    field: "first_column", // To change the field name in actual table
  },
});


Enter fullscreen mode Exit fullscreen mode

Composite Unique Key

To create a composite unique key, give the same name to the constraint in all the columns you want to include in the composite unique key



const ModelName = sequelize.define("tablename", {
  firstColumn: {
    type: Sequelize.INTEGER,
    unique: "compositeIndex",
  },
  secondColumn: {
    type: Sequelize.INTEGER,
    unique: "compositeIndex",
  },
});


Enter fullscreen mode Exit fullscreen mode

They can also be created using indexes



const ModelName = sequelize.define(
  "tablename",
  {
    firstColumn: Sequelize.INTEGER,
    secondColumn: Sequelize.INTEGER,
  },
  {
    indexes: [
      {
        unique: true,
        fields: ["firstColumn", "secondColumn"],
      },
    ],
  }
);


Enter fullscreen mode Exit fullscreen mode

Getters and Setters

Getters can be used to get the value of the column after some processing.
Setters can be used to process the value before saving it into the table.



const Employee = sequelize.define("employee", {
  name: {
    type: Sequelize.STRING,
    allowNull: false,
    get() {
      const title = this.getDataValue("title");
      // 'this' allows you to access attributes of the instance
      return this.getDataValue("name") + " (" + title + ")";
    },
  },
  title: {
    type: Sequelize.STRING,
    allowNull: false,
    set(val) {
      this.setDataValue("title", val.toUpperCase());
    },
  },
});

Employee.create({ name: "John Doe", title: "senior engineer" }).then(
  (employee) => {
    console.log(employee.get("name")); // John Doe (SENIOR ENGINEER)
    console.log(employee.get("title")); // SENIOR ENGINEER
  }
);


Enter fullscreen mode Exit fullscreen mode

For more in-depth information about Getters and Setters, check out the official docs

Validations

Validations are automatically run on create, update and save

Per Attribute Validations



const ModelName = sequelize.define("tablename", {
  firstColumn: {
    type: Sequelize.STRING,
    validate: {
      is: ["^[a-z]+$", "i"], // will only allow letters
      is: /^[a-z]+$/i, // same as the previous example using real RegExp
      not: ["[a-z]", "i"], // will not allow letters
      isEmail: true, // checks for email format (foo@bar.com)
      isUrl: true, // checks for url format (http://foo.com)
      isIP: true, // checks for IPv4 (129.89.23.1) or IPv6 format
      isIPv4: true, // checks for IPv4 (129.89.23.1)
      isIPv6: true, // checks for IPv6 format
      isAlpha: true, // will only allow letters
      isAlphanumeric: true, // will only allow alphanumeric characters, so "_abc" will fail
      isNumeric: true, // will only allow numbers
      isInt: true, // checks for valid integers
      isFloat: true, // checks for valid floating point numbers
      isDecimal: true, // checks for any numbers
      isLowercase: true, // checks for lowercase
      isUppercase: true, // checks for uppercase
      notNull: true, // won't allow null
      isNull: true, // only allows null
      notEmpty: true, // don't allow empty strings
      equals: "specific value", // only allow a specific value
      contains: "foo", // force specific substrings
      notIn: [["foo", "bar"]], // check the value is not one of these
      isIn: [["foo", "bar"]], // check the value is one of these
      notContains: "bar", // don't allow specific substrings
      len: [2, 10], // only allow values with length between 2 and 10
      isUUID: 4, // only allow uuids
      isDate: true, // only allow date strings
      isAfter: "2011-11-05", // only allow date strings after a specific date
      isBefore: "2011-11-05", // only allow date strings before a specific date
      max: 23, // only allow values <= 23
      min: 23, // only allow values >= 23
      isCreditCard: true, // check for valid credit card numbers

      // Examples of custom validators:
      isEven(value) {
        if (parseInt(value) % 2 !== 0) {
          throw new Error("Only even values are allowed!");
        }
      },
    },
  },
});


Enter fullscreen mode Exit fullscreen mode

Model Wide Validations



const ModelName = sequelize.define(
  "tablename",
  {
    firstColumn: Sequelize.INTEGER,
    secondColumn: Sequelize.INTEGER,
  },
  {
    validate: {
      // Define your Model Wide Validations here
      checkSum() {
        if (this.firstColumn + this.secondColumn < 10) {
          throw new Error("Require sum of columns >=10");
        }
      },
    },
  }
);


Enter fullscreen mode Exit fullscreen mode

Timestamps



const ModelName = sequelize.define(
  "tablename",
  {
    firstColumn: Sequelize.INTEGER,
  },
  {
    timestamps: true, // Enable timestamps
    createdAt: false, // Don't create createdAt
    updatedAt: false, // Don't create updatedAt
    updatedAt: "updateTimestamp", // updatedAt should be called updateTimestamp
  }
);


Enter fullscreen mode Exit fullscreen mode

Database Synchronization

Sequelize can automatically create the tables, relations and constraints as defined in the models



ModelName.sync(); // Create the table if not already present

// Force the creation
ModelName.sync({ force: true }); // this will drop the table first and re-create it afterwards

ModelName.drop(); // drop the tables


Enter fullscreen mode Exit fullscreen mode

You can manage all models at once using sequelize instead



sequelize.sync(); // Sync all models that aren't already in the database

sequelize.sync({ force: true }); // Force sync all models

sequelize.sync({ force: true, match: /_test$/ }); // Run .sync() only if database name ends with '_test'

sequelize.drop(); // Drop all tables


Enter fullscreen mode Exit fullscreen mode

Expansion of Models

Sequelize Models are ES6 classes. We can easily add custom instance or class level methods.



const ModelName = sequelize.define("tablename", {
  firstColumn: Sequelize.STRING,
  secondColumn: Sequelize.STRING,
});
// Adding a class level method
ModelName.classLevelMethod = function () {
  return "This is a Class level method";
};

// Adding a instance level method
ModelName.prototype.instanceLevelMethod = function () {
  return [this.firstColumn, this.secondColumn].join(" ");
};


Enter fullscreen mode Exit fullscreen mode

Indexes



const User = sequelize.define(
  "User",
  {
    /* attributes */
  },
  {
    indexes: [
      // Create a unique index on email
      {
        unique: true,
        fields: ["email"],
      },

      // Creates a gin index on data with the jsonb_path_ops operator
      {
        fields: ["data"],
        using: "gin",
        operator: "jsonb_path_ops",
      },

      // By default index name will be [table]_[fields]
      // Creates a multi column partial index
      {
        name: "public_by_author",
        fields: ["author", "status"],
        where: {
          status: "public",
        },
      },

      // A BTREE index with an ordered field
      {
        name: "title_index",
        using: "BTREE",
        fields: [
          "author",
          {
            attribute: "title",
            collate: "en_US",
            order: "DESC",
            length: 5,
          },
        ],
      },
    ],
  }
);


Enter fullscreen mode Exit fullscreen mode

Associations

Defining Associations

There are four types of definitions. They are used in pairs.
For the example lets define two Models



const Foo = sequelize.define("foo" /* ... */);
const Bar = sequelize.define("bar" /* ... */);


Enter fullscreen mode Exit fullscreen mode

The model whose function we will be calling is called the source model, and the model which is passed as a parameter is called the target model.

hasOne



Foo.hasOne(Bar, {
  /* options */
});


Enter fullscreen mode Exit fullscreen mode

This states that a One-to-One relationship exists between Foo and Bar with foreign key defined in Bar

belongsTo



Foo.belongsTo(Bar, {
  /* options */
});


Enter fullscreen mode Exit fullscreen mode

This states that a One-to-One or One-to-Many relationship exists between Foo and Bar with foreign key defined in Foo

hasMany



Foo.hasMany(Bar, {
  /* options */
});


Enter fullscreen mode Exit fullscreen mode

This states that a One-to-Many relationship exists between Foo and Bar with foreign key defined in Bar

belongsToMany



Foo.belongsToMany(Bar, {
  // REQUIRED
  through: "C", // Model can also be passed here
  /* options */
});


Enter fullscreen mode Exit fullscreen mode

This states that a Many-to-Many relationship exists between Foo and Bar through a junction table C

Relations

One to One

To setup a One-to-One relationship, we have to simply write



Foo.hasOne(Bar);
Bar.belongsTo(Foo);


Enter fullscreen mode Exit fullscreen mode

In the above case, no option was passed. This will auto create a foreign key column in Bar referencing to the primary key of Foo. If the column name of PK of Foo is email, the column formed in Bar will be fooEmail.

Options

The following options can be passed to customize the relation.



Foo.hasOne(Bar, {
  foreignKey: "customNameForFKColumn", // Name for new column added to Bar
  sourceKey: "email", // Column in Foo that FK will reference to
  // The possible choices are RESTRICT, CASCADE, NO ACTION, SET DEFAULT and SET NULL
  onDelete: "RESTRICT", // Default is SET NULL
  onUpdate: "RESTRICT", // Default is CASCADE
});
Bar.belongsTo(Foo, {
  foreignKey: "customNameForFKColumn", // Name for new column added to Bar
});


Enter fullscreen mode Exit fullscreen mode

One to Many

To setup a One-to-One relationship, we have to simply write



Foo.hasMany(Bar);
Bar.belongsTo(Foo);


Enter fullscreen mode Exit fullscreen mode

In the above case, no option was passed. This will auto create a foreign key column in Bar referencing to the primary key of Foo. If the column name of PK of Foo is email, the column formed in Bar will be fooEmail.

Options

The following options can be passed to customize the relation.



Foo.hasMany(Bar, {
  foreignKey: "customNameForFKColumn", // Name for new column added to Bar
  sourceKey: "email", // Column in Foo that FK will reference to
  // The possible choices are RESTRICT, CASCADE, NO ACTION, SET DEFAULT and SET NULL
  onDelete: "RESTRICT", // Default is SET NULL
  onUpdate: "RESTRICT", // Default is CASCADE
});
Bar.belongsTo(Foo, {
  foreignKey: "customNameForFKColumn", // Name for new column added to Bar
});


Enter fullscreen mode Exit fullscreen mode

Many to Many

To setup a Many-to-Many relationship, we have to simply write



// This will create a new table rel referencing the PK(by default) of both the tables
Foo.belongsToMany(Bar, { through: "rel" });
Bar.belongsToMany(Foo, { through: "rel" });


Enter fullscreen mode Exit fullscreen mode

Options

The following options can be passed to customize the relation.



Foo.belongsToMany(Bar, {
  as: "Bar",
  through: "rel",
  foreignKey: "customNameForFoo", // Custom name for column in rel referencing to Foo
  sourceKey: "name", // Column in Foo which rel will reference to
});
Bar.belongsToMany(Foo, {
  as: "Foo",
  through: "rel",
  foreignKey: "customNameForBar", // Custom name for column in rel referencing to Bar
  sourceKey: "name", // Column in Foo which rel will reference to
});


Enter fullscreen mode Exit fullscreen mode

Instances

Creating Instances

There are two ways to create instances

build

We can use build method to create non-persistent(not saved to table) instances. They will automatically get the default values as stated while defining the Model.
To save to the table we need to save these instances explicitly.



const instance = ModelName.build({
  firstColumn: "Lorem Ipsum",
  secondColumn: "Dotor",
});
// To save this instance to the db
instance.save().then((savedInstance) => {});


Enter fullscreen mode Exit fullscreen mode

create

We can create a method to create persistent(saved to table) instances



const instance = ModelName.create({
  firstColumn: "Lorem Ipsum",
  secondColumn: "Dotor",
});


Enter fullscreen mode Exit fullscreen mode

Mutating Instances

Update

There are two ways to update any instance



// Way 1
instance.secondColumn = "Updated Dotor";
instance.save().then(() => {});
// To update only some of the modified fields
instance.save({ fields: ["secondColumn"] }).then(() => {});

// Way 2
instance
  .update({
    secondColumn: "Updated Dotor",
  })
  .then(() => {});
// To update only some of the modified fields
instance
  .update(
    {
      secondColumn: "Updated Dotor",
    },
    { fields: ["secondColumn"] }
  )
  .then(() => {});


Enter fullscreen mode Exit fullscreen mode

Delete

To delete/destroy any instance



instance.destroy().then(() => {});


Enter fullscreen mode Exit fullscreen mode

Using Models

Methods

findByPk

Returns the row with the given value of Primary Key.



ModelName.findByPK(PKvalue).then((foundResult) => {});


Enter fullscreen mode Exit fullscreen mode

findOne

Returns the first row with the given conditions.



ModelName.findOne({
  // Optional options
  // Filtering results using where
  where: { firstColumn: "value" },
  // Returning only specified columns
  attributes: ["firstColumn", "secondColumn"],
}).then((foundResult) => {});


Enter fullscreen mode Exit fullscreen mode

findOrCreate

Returns the row found with given conditions. If no such row exists, creates one and returns that instead



ModelName.findOrCreate({
  // Conditions that must be met
  where: { firstColumn: "lorem ipsum" },
  // Value of other columns to be set if no such row found
  defaults: { secondColumn: "dotor" },
}).then(([result, created]) => {}); //Created is a bool which tells created or not


Enter fullscreen mode Exit fullscreen mode

findAll

Returns all the rows satisfying the conditions



ModelName.findAll({
  // Optional Options
  where: {
    firstColumn: "lorem ipsum",
  },
  offset: 10,
  limit: 2,
}).then((results) => {});


Enter fullscreen mode Exit fullscreen mode

findAndCountAll

Returns all the rows satisfying the conditions along with their count



ModelName.findAndCountAll({
  where: {
    firstColumn: "lorem ipsum",
  },
}).then((results) => {
  console.log(results.count);
  console.log(results.rows);
});


Enter fullscreen mode Exit fullscreen mode

count

Returns number of rows satisfying the conditions



ModelName.count({
  where: {
    firstColumn: "lorem ipsum",
  },
}).then((c) => {});


Enter fullscreen mode Exit fullscreen mode

max

Returns the value of the column with max value with given conditions



ModelName.max("age", {
  where: {
    firstColumn: "lorem ipsum",
  },
}).then((maxAge) => {});


Enter fullscreen mode Exit fullscreen mode

min

Returns the value of the column with min value with given conditions



ModelName.min("age", {
  where: {
    firstColumn: "lorem ipsum",
  },
}).then((minAge) => {});


Enter fullscreen mode Exit fullscreen mode

sum

Returns the sum of all the values of the columns with given conditions



ModelName.sum({
  where: {
    firstColumn: "lorem ipsum",
  },
}).then((sumAge) => {});


Enter fullscreen mode Exit fullscreen mode

Filtering

where

where can be used to filter the results we work on

We can directly pass the values



ModelName.findAll({
  where: {
    firstColumn: "lorem ipsum",
  },
});


Enter fullscreen mode Exit fullscreen mode

We can use AND and OR



const Op = Sequelize.Op;
ModelName.findAll({
  where: {
    [Op.and]: [{ secondColumn: 5 }, { thirdColumn: 6 }],
    [Op.or]: [{ secondColumn: 5 }, { secondColumn: 6 }],
  },
});


Enter fullscreen mode Exit fullscreen mode

We can use various other operators



const Op = Sequelize.Op;
ModelName.findAll({
  where: {
    firstColumn: {
      [Op.ne]: "lorem ipsum dotor", // Not equal to
    },
  },
});


Enter fullscreen mode Exit fullscreen mode

We can mix and match too



const Op = Sequelize.Op;
ModelName.findAll({
  where: {
    [Op.or]: {
      [Op.lt]: 1000,
      [Op.eq]: null,
    },
  },
});


Enter fullscreen mode Exit fullscreen mode

Operators

Here is the full list of Operators



const Op = Sequelize.Op

[Op.and]: [{a: 5}, {b: 6}] // (a = 5) AND (b = 6)
[Op.or]: [{a: 5}, {a: 6}]  // (a = 5 OR a = 6)
[Op.gt]: 6,                // > 6
[Op.gte]: 6,               // >= 6
[Op.lt]: 10,               // < 10
[Op.lte]: 10,              // <= 10
[Op.ne]: 20,               // != 20
[Op.eq]: 3,                // = 3
[Op.is]: null              // IS NULL
[Op.not]: true,            // IS NOT TRUE
[Op.between]: [6, 10],     // BETWEEN 6 AND 10
[Op.notBetween]: [11, 15], // NOT BETWEEN 11 AND 15
[Op.in]: [1, 2],           // IN [1, 2]
[Op.notIn]: [1, 2],        // NOT IN [1, 2]
[Op.like]: '%hat',         // LIKE '%hat'
[Op.notLike]: '%hat'       // NOT LIKE '%hat'
[Op.iLike]: '%hat'         // ILIKE '%hat' (case insensitive) (PG only)
[Op.notILike]: '%hat'      // NOT ILIKE '%hat'  (PG only)
[Op.startsWith]: 'hat'     // LIKE 'hat%'
[Op.endsWith]: 'hat'       // LIKE '%hat'
[Op.substring]: 'hat'      // LIKE '%hat%'
[Op.regexp]: '^[h|a|t]'    // REGEXP/~ '^[h|a|t]' (MySQL/PG only)
[Op.notRegexp]: '^[h|a|t]' // NOT REGEXP/!~ '^[h|a|t]' (MySQL/PG only)
[Op.iRegexp]: '^[h|a|t]'    // ~* '^[h|a|t]' (PG only)
[Op.notIRegexp]: '^[h|a|t]' // !~* '^[h|a|t]' (PG only)
[Op.like]: { [Op.any]: ['cat', 'hat']}
                           // LIKE ANY ARRAY['cat', 'hat'] - also works for iLike and notLike
[Op.overlap]: [1, 2]       // && [1, 2] (PG array overlap operator)
[Op.contains]: [1, 2]      // @> [1, 2] (PG array contains operator)
[Op.contained]: [1, 2]     // <@ [1, 2] (PG array contained by operator)
[Op.any]: [2,3]            // ANY ARRAY[2, 3]::INTEGER (PG only)

[Op.col]: 'user.organization_id' // = "user"."organization_id", with dialect specific column identifiers, PG in this example
[Op.gt]: { [Op.all]: literal('SELECT 1') }
                          // > ALL (SELECT 1)
[Op.contains]: 2           // @> '2'::integer (PG range contains element operator)
[Op.contains]: [1, 2]      // @> [1, 2) (PG range contains range operator)
[Op.contained]: [1, 2]     // <@ [1, 2) (PG range is contained by operator)
[Op.overlap]: [1, 2]       // && [1, 2) (PG range overlap (have points in common) operator)
[Op.adjacent]: [1, 2]      // -|- [1, 2) (PG range is adjacent to operator)
[Op.strictLeft]: [1, 2]    // << [1, 2) (PG range strictly left of operator)
[Op.strictRight]: [1, 2]   // >> [1, 2) (PG range strictly right of operator)
[Op.noExtendRight]: [1, 2] // &< [1, 2) (PG range does not extend to the right of operator)
[Op.noExtendLeft]: [1, 2]  // &> [1, 2) (PG range does not extend to the left of operator)


Enter fullscreen mode Exit fullscreen mode

order



ModelName.findAll({
  order: [
    ["firstColumn", "DESC"],
    ["secondColumn", "ASC"],
  ],
});


Enter fullscreen mode Exit fullscreen mode

For much more detailed information on ordering, check out the official docs

Pagination and Limiting



ModelName.findAll({
  offset: 5, // Skip the first five results
  limit: 5, // Return only five results
});


Enter fullscreen mode Exit fullscreen mode

Checkout my blogs repo

Send pull requests to add/modify to this post.

GitHub logo projectescape / blogs-reference

A repository which contains the source complementing all the blogs I write




Top comments (12)

Collapse
 
kasir-barati profile image
Mohammad Jawad (Kasir) Barati

Hi. I have the same problem with Sequelize, I could not understand the aliases in Sequelize. can you write a post about it?

for example, I create order & user models. now i wanna define aliases for them:
user has multiple order, order has one user.
can you simplify it for me? how should i define the aliases & how should i use them in the find queries?

Collapse
 
tylerjusfly profile image
Tyler

I need to figure this out to...

Collapse
 
kasir-barati profile image
Mohammad Jawad (Kasir) Barati

Hello Momoh

I like to share one thing with you. I am no longer use Sequelize. I switch to prisma and now I got over Sequelize and its endless bottlenecks. Just try prisma

Collapse
 
juanccq profile image
Juan Carlos Choque Quispe

Great post, as Sequelize now creates a model with ES6 classes, could you add an example of this, specifically the relationship between other models.

I tried to do but I think there is no enough documentation.

Collapse
 
projectescape profile image
Aniket

This took way more time than I expected, but life will be much easier moving forward 😌

Collapse
 
chinedumonyema profile image
Chinedum Onyema

Great summary. Thank you.

Collapse
 
samihmz profile image
Sami Hamaizi

that was so helpfull, thank you

Collapse
 
sm0ke profile image
Sm0ke

Great post. Thank you!

Collapse
 
phamminhhaiau12035071 profile image
PhamMinhHaiAu-12035071

great post. vote Sequelize and typeorm

Collapse
 
projectescape profile image
Aniket

Haven't used typeorm yet!

Collapse
 
k3sha7 profile image
k3sha7

What about migrations?

Collapse
 
arinmovsesian profile image
Arin Movsesian

👌