Sequelize
database
ORM
table names
programming

How to make Sequelize use singular table names

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Sequelize pluralizes model names by default, so a model named User typically maps to a table named Users. If your schema uses singular table names, or you want strict control over naming, you need to override that convention explicitly instead of relying on the default inflector.

Use freezeTableName on a Model

The most direct fix is to set freezeTableName: true in the model definition. That tells Sequelize to use the model name as the table name without pluralizing it.

javascript
1const { DataTypes, Sequelize } = require("sequelize");
2
3const sequelize = new Sequelize("sqlite::memory:");
4
5const User = sequelize.define("User", {
6  name: DataTypes.STRING,
7}, {
8  freezeTableName: true,
9});
10
11console.log(User.getTableName());

With that option, the table name stays User instead of becoming Users.

This is often enough when you only need singular names for a few models or when you are integrating with an existing schema.

Set It Globally for the Whole Sequelize Instance

If you want the same rule everywhere, configure it once in the Sequelize constructor under define.

javascript
1const { Sequelize, DataTypes } = require("sequelize");
2
3const sequelize = new Sequelize("sqlite::memory:", {
4  define: {
5    freezeTableName: true,
6  },
7});
8
9const Product = sequelize.define("Product", {
10  sku: DataTypes.STRING,
11});
12
13const Order = sequelize.define("Order", {
14  total: DataTypes.INTEGER,
15});
16
17console.log(Product.getTableName());
18console.log(Order.getTableName());

This is cleaner than repeating the same option on every model when the project has a consistent naming policy.

Use tableName When You Need Exact Control

Sometimes singular naming is only part of the requirement. You may need lowercase names, snake case, or a legacy table name that does not match the model at all. In that case, specify tableName directly.

javascript
1const Customer = sequelize.define("Customer", {
2  email: DataTypes.STRING,
3}, {
4  tableName: "customer",
5  freezeTableName: true,
6});

tableName is the strongest override because it tells Sequelize the exact table to use. freezeTableName just prevents pluralization of the model name.

In other words:

  • use freezeTableName when the model name already matches the table name you want
  • use tableName when the database name needs to be specified exactly

Keep Models, Migrations, and Associations Aligned

Changing table naming rules affects more than model definitions. Migrations, seeders, and associations also need to agree with the same table names.

For example, a migration creating a singular table might look like this:

javascript
1module.exports = {
2  async up(queryInterface, Sequelize) {
3    await queryInterface.createTable("User", {
4      id: {
5        allowNull: false,
6        autoIncrement: true,
7        primaryKey: true,
8        type: Sequelize.INTEGER,
9      },
10      name: {
11        type: Sequelize.STRING,
12      },
13    });
14  },
15
16  async down(queryInterface) {
17    await queryInterface.dropTable("User");
18  },
19};

If the model expects User but the migration created Users, the ORM configuration looks correct while queries still fail at runtime.

Associations also deserve a quick check. Relationship helpers may generate foreign key names or alias assumptions that reflect model naming, so verify the generated SQL if your schema is strict.

Prefer Explicit Naming Over Guessing

The deeper rule is this: if naming matters, make it explicit. Default pluralization is convenient for greenfield apps, but legacy databases and team conventions usually benefit from direct configuration. freezeTableName and tableName exist so you do not have to guess how the inflector will interpret every model name.

That explicitness also helps new developers. They can read the model definition and immediately see the real database table instead of deducing it from conventions.

Common Pitfalls

  • Setting freezeTableName on one model but forgetting the rest creates a mixed naming scheme that is hard to maintain.
  • Expecting freezeTableName to rename an existing database table is incorrect. It only changes how Sequelize maps the model.
  • Updating model definitions without updating migrations causes runtime failures because the ORM and schema disagree.
  • Assuming freezeTableName is enough for custom lowercase or legacy names is risky. Use tableName when the exact name matters.
  • Ignoring generated association behavior can produce confusing foreign key or join-table names in stricter schemas.

Summary

  • Sequelize pluralizes table names by default unless you override the behavior.
  • Use freezeTableName: true to keep the model name singular.
  • Set the option globally under define when the whole project follows the same rule.
  • Use tableName for exact control over the database table name.
  • Keep models, migrations, and associations aligned so the naming rule is consistent everywhere.

Course illustration
Course illustration

All Rights Reserved.