tezvyn:

Sequelize Scopes: Reusable Query Shortcuts

AI-drafted, machine-checkedSource: sequelize.orgadvanced

Sequelize scopes are named shortcuts for common query conditions, letting you define `where` or `include` clauses once and reuse them. Use them to keep code DRY, like an `active` scope. The footgun: a `defaultScope` is always on unless you call `.unscoped()`.

WHY IT EXISTS Sequelize scopes were created to solve the problem of repeating complex query logic across an application. Without them, you might write the same where, include, or limit options in many different places, making the code hard to maintain and prone to errors. Scopes centralize this logic on the model itself.

THE MENTAL MODEL Think of scopes as named functions for your database queries. Instead of manually building a query object like { where: { status: 'active' }, include: [User] } every time, you define a scope called activeWithUsers once on the model. Afterwards, you can simply call Model.scope('activeWithUsers').findAll() to get the same result with cleaner, more readable code.

HOW IT WORKS You define scopes in your model's options under the scopes key. Each scope is an object containing query options (like where, include, limit). A special defaultScope can also be defined, which is applied to all find-type queries automatically unless you explicitly disable it. To use a scope, you call Model.scope('yourScopeName'), which returns a new, scoped model instance. You can then call methods like .findAll() or .update() on it. You can also apply multiple scopes; their where and include attributes are merged, while other properties are overwritten by the last scope applied.

WHEN TO USE IT Use scopes for any query you run frequently. This is ideal for standard filters like active or deleted records, for including common associations with a shortcut like withUsers, or for creating complex, parameterized searches like accessLevel(5). They are perfect for enforcing business logic at the model level, ensuring queries are consistent across your app.

WHEN NOT TO USE IT Avoid scopes for one-off, highly specific queries that won't be reused. The overhead of defining a scope isn't worth it for a query you'll only run once. Be especially cautious with the defaultScope; its implicit nature can make queries harder to debug if a developer isn't aware it's silently filtering every request. If a query needs to be explicit, build it directly.

ONE CANONICAL EXAMPLE Define a Project model with a defaultScope for active projects and a deleted scope for deleted ones. Project.init({ ... }, { defaultScope: { where: { active: true } }, scopes: { deleted: { where: { deleted: true } } }, sequelize }); A call to Project.findAll() generates SQL with WHERE active = true because the default scope is always applied. A call to Project.scope('deleted').findAll() generates SQL with WHERE deleted = true, overriding the default scope. To combine them, Project.scope('defaultScope', 'deleted').findAll() generates SQL with WHERE active = true AND deleted = true.

Read the original → sequelize.org

Get five bites like this every day.

Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.