What are Sequelize Models?

Welcome to our tutorial on Sequelize models! Imagine you’re building a car. The chassis, engine, and body panels are the blueprint that defines what the car is and how it functions. In a similar way, a Sequelize model is the blueprint for a database table. It represents the structure of the table and allows you to interact with your data using object-oriented JavaScript. By the end of this lesson, you’ll know how to define a model, extend it with custom methods, add validations, and use it effectively in your code.

Defining a Sequelize Model

A Sequelize model is essentially a JavaScript class that maps to a table in your database. The class name often is a singular noun (like User), and the table in your database is typically the plural version of that name (for example, Users). The model defines the attributes (columns) of the table and their data types.

Let’s look at a basic example of a User model:

const { Model } = require('sequelize');

module.exports = (sequelize, DataTypes) => {
  class User extends Model {
    // Helper method for defining associations.
    static associate(models) {
      // define association here
    }
  }
  User.init({
    // Model attributes are defined here
    firstName: {
      type: DataTypes.STRING,
      allowNull: false
    },
    lastName: {
      type: DataTypes.STRING,
      allowNull: false
    },
    bio: {
      type: DataTypes.TEXT
      // allowNull defaults to true
    }
  }, {
    // Other model options go here
    sequelize,        // pass the connection instance
    modelName: 'User' // choose the model name
  });
  
  return User;
};
  

In this code, the User class extends Sequelize's Model and defines three attributes: firstName, lastName, and bio. These correspond to columns in the Users table. Notice how we pass the sequelize instance and define the modelName—this ties the model to the database.

Extending the Functionality of a Model

Just as you might add custom features to a car, you can extend a Sequelize model with additional properties and methods. These can be class-level methods (static methods) or instance-level methods that add functionality specific to your application.

Consider the following example:

class User extends Model {
  static classLevelMethod() {
    return 'foo';
  }
  instanceLevelMethod() {
    return 'bar';
  }
  getFullName() {
    return [this.firstName, this.lastName].join(' ');
  }
}
User.init({
  firstName: DataTypes.STRING,
  lastName: DataTypes.STRING,
  bio: DataTypes.TEXT
}, { sequelize, modelName: 'User' });

console.log(User.classLevelMethod()); // Outputs: 'foo'
const user = User.build({ firstName: 'Jane', lastName: 'Doe' });
console.log(user.instanceLevelMethod()); // Outputs: 'bar'
console.log(user.getFullName());         // Outputs: 'Jane Doe'
  

In this example, we add a class-level method, an instance-level method, and a custom method to generate a full name. This flexibility allows you to add behavior directly to your models, making it easier to work with your data.

Adding Validations to a Model

Validations ensure that the data you try to store in your database meets certain criteria before SQL is executed. For example, you may want to ensure that a user's first name and last name are not null. While some of this can be enforced at the database level, Sequelize allows you to add custom validations in your model definition.

Here’s how you might add validations to a User model:

const { Model } = require('sequelize');

module.exports = (sequelize, DataTypes) => {
  class User extends Model {
    static associate(models) {
      // define association here
    }
  }

  User.init({
    firstName: {
      type: DataTypes.STRING,
      allowNull: false,
      validate: {
        notNull: {
          msg: 'Please enter a first name'
        }
      }
    },
    lastName: {
      type: DataTypes.STRING,
      allowNull: false,
      validate: {
        notNull: {
          msg: 'Please enter a last name'
        }
      }
    },
    bio: {
      type: DataTypes.TEXT
    }
  }, {
    sequelize,
    modelName: 'User'
  });

  return User;
};
  

With these validations, if you try to create a User without a first or last name, Sequelize will throw a validation error with a custom message. This helps catch issues early before the data even reaches your database.

Using and Generating Models

Once your model is defined, you can use it to interact with your database in an object-oriented manner. To use a model, import it from your db/models/index.js file and then work with it like any other class.

For example:

const { User } = require('./db/models');

// Create a new user instance
const newUser = User.build({ firstName: 'John', lastName: 'Smith', bio: 'A brief bio.' });

// Save the user to the database
newUser.save()
  .then(user => {
    console.log('User created:', user.getFullName());
  })
  .catch(error => {
    console.error('Error creating user:', error);
  });
  

Additionally, you can generate a model (along with a migration file) using the Sequelize CLI:

npx sequelize model:generate --name User --attributes name:string
  

This command creates a file named user.js in the models folder and a corresponding migration file (with a timestamp) in the migrations folder. The generated files follow the conventions shown above.

Real-World Applications and Best Practices

Using Sequelize models in your projects provides a clean abstraction over your database. Imagine if every time you wanted to update a record you had to write a raw SQL query—models make this process intuitive and maintainable.

Best practices include:

This approach not only simplifies development but also fosters collaboration in teams, as every developer has a clear, consistent interface for interacting with the database.

Conclusion

In this tutorial, you learned that a Sequelize model is much more than just a representation of a database table. It is a powerful, object-oriented blueprint that lets you interact with your data in a natural way. By extending models with custom methods and validations, you can create a rich, maintainable data layer that evolves along with your application. Whether you are building a simple project or a complex enterprise application, Sequelize models empower you to write clean, secure, and efficient code.

With this knowledge, you’re ready to integrate Sequelize models into your projects and take advantage of all the benefits of using an ORM in your development workflow. Happy coding!