drizzle-team / drizzle-team/drizzle-orm
[FEATURE]: DB Table Default Scopes
- Dominant language
- TypeScript
- Stars
- 35.8k
- Forks
- 1.6k
- Avg merge
- 2d 7h
- Merged PRs (30d)
- 4
Description
### Feature hasn't been suggested before.
- [x] I have verified this feature I'm about to request hasn't been suggested before.
### Describe the enhancement you want to request
In many applications, we need a consistent way to apply default filters to all queries on a table. Currently you have to create a function that returns the DB with these scopes applied. This is annoying as it can be easy to use the db directly and not the function getDb.
Common examples:
* Soft deletes (`deleted_at IS NULL`)
* Multi-tenant isolation (`organization_id = X`)
* Status filtering (e.g. only `active = true`)
Right now with Drizzle, this logic has to be manually added to every query or the DB has to be wrapped in a helper function, which:
* Is error-prone (easy to forget in one place)
* Leads to duplicated logic across the codebase
* Makes it harder to enforce invariants like tenant isolation
---
### Proposed Solution
Add support for **default scopes** (or global query filters) at the table level.
Example API (one possible direction):
```ts
const users = pgTable('users', {
id: serial('id').primaryKey(),
organizationId: integer('organization_id'),
deletedAt: timestamp('deleted_at'),
}).withDefaultScope((qb, ctx) =>
qb.where(
and(
isNull(users.deletedAt),
eq(users.organizationId, ctx.organizationId)
)
)
);
```
Then:
```ts
db.select().from(users)
```
Would automatically apply:
```sql
WHERE deleted_at IS NULL AND organization_id = ?
```
---
### Requirements / Considerations
* Ability to **override or disable** the default scope when needed:
```ts
db.select().from(users).unscoped()
```
* Ability to **compose scopes** (e.g. multiple conditions)
* Support for **context-aware scopes** (e.g. tenant ID passed via request context)
* Should work consistently across:
* `select`
* `update`
* `delete`
---
### Alternatives Considered
* Manually wrapping queries in helper functions → leads to fragmentation
* Custom repository layer → adds boilerplate and defeats Drizzle’s lightweight design
---
### Why this matters
This is a pretty standard feature in ORMs (e.g. Rails ActiveRecord default scopes), and it becomes essential for:
* Multi-tenant apps
* Soft delete patterns
* Enforcing global data constraints safely
---
Happy to help iterate on API design if this is something you’d consider adding.
Contributor guide
Assessment
This issue has not been assessed yet.