Drizzle ORM Patterns
Overview
Expert guide for building type-safe database applications with Drizzle ORM. Covers schema definition, relations, queries, transactions, and migrations for all supported databases.
When to Use
- Defining database schemas with tables, columns, and constraints
- Creating relations between tables (one-to-one, one-to-many, many-to-many)
- Writing type-safe CRUD queries
- Implementing complex joins and aggregations
- Managing database transactions with rollback
- Setting up migrations with Drizzle Kit
- Working with PostgreSQL, MySQL, SQLite, MSSQL, or CockroachDB
Quick Reference
| Database |
Table Function |
Import |
| PostgreSQL |
pgTable() |
drizzle-orm/pg-core |
| MySQL |
mysqlTable() |
drizzle-orm/mysql-core |
| SQLite |
sqliteTable() |
drizzle-orm/sqlite-core |
| MSSQL |
mssqlTable() |
drizzle-orm/mssql-core |
| Operation |
Method |
Example |
| Insert |
db.insert() |
db.insert(users).values({...}) |
| Select |
db.select() |
db.select().from(users).where(eq(...)) |
| Update |
db.update() |
db.update(users).set({...}).where(...) |
| Delete |
db.delete() |
db.delete(users).where(...) |
| Transaction |
db.transaction() |
db.transaction(async (tx) => {...}) |
Instructions
- Identify your database dialect - Choose PostgreSQL, MySQL, SQLite, MSSQL, or CockroachDB
- Define your schema - Use the appropriate table function (pgTable, mysqlTable, etc.)
- Set up relations - Define relations using
relations() or defineRelations()
- Initialize the database client - Create your Drizzle client with proper credentials
- Write queries - Use the query builder for type-safe CRUD operations
- Handle transactions - Wrap multi-step operations in transactions when needed
- Set up migrations - Configure Drizzle Kit for schema management
Examples
Example 1: Basic Schema and Query
import { pgTable, serial, text } from 'drizzle-orm/pg-core';
import { drizzle } from 'drizzle-orm/node-postgres';
import { eq } from 'drizzle-orm';
export const users = pgTable('users', {
id: serial('id').primaryKey(),
name: text('name').notNull(),
email: text('email').notNull().unique(),
});
const db = drizzle(process.env.DATABASE_URL);
const [user] = await db.select().from(users).where(eq(users.id, 1));
Example 2: CRUD Operations
import { eq } from 'drizzle-orm';
// Insert
const [newUser] = await db.insert(users).values({
name: 'John',
email: 'john@example.com',
}).returning();
// Update
await db.update(users)
.set({ name: 'John Updated' })
.where(eq(users.id, 1));
// Delete
await db.delete(users).where(eq(users.id, 1));
Example 3: Transaction with Rollback
await db.transaction(async (tx) => {
const [from] = await tx.select().from(accounts)
.where(eq(accounts.userId, fromId));
if (from.balance < amount) {
tx.rollback();
}
await tx.update(accounts)
.set({ balance: sql`${accounts.balance} - ${amount}` })
.where(eq(accounts.userId, fromId));
});
See references/transactions.md for advanced transaction patterns.
Best Practices
- Type Safety: Always use TypeScript and leverage
$inferInsert / $inferSelect
- Relations: Define relations using the relations() API for nested queries
- Transactions: Use transactions for multi-step operations that must succeed together
- Migrations: Use
generate + migrate in production, push for development
- Indexes: Add indexes on frequently queried columns and foreign keys
- Soft Deletes: Use
deletedAt timestamp instead of hard deletes when possible
- Pagination: Use cursor-based pagination for large datasets
- Query Optimization: Use
.limit() and .where() to fetch only needed data
Constraints and Warnings
- Foreign Key Constraints: Always define references using arrow functions
() => table.column to avoid circular dependency issues
- Transaction Rollback: Calling
tx.rollback() throws an exception - use try/catch if needed
- Returning Clauses: Not all databases support
.returning() - check your dialect compatibility
- Batch Operations: Large batch inserts may hit database limits - chunk into smaller batches
- Migrations in Production: Always test migrations in staging before applying to production
References
Core Concepts
- references/schema-definition.md - Complete schema definition for all databases (PostgreSQL, MySQL, SQLite), column types, indexes, and constraints
- references/relations.md - One-to-one, one-to-many, many-to-many relations with v1 and v2 syntax
- references/queries-joins-aggregations.md - CRUD operations, query operators, joins, aggregations, and pagination
Advanced Topics
- references/transactions.md - Transaction patterns, rollback handling, nested transactions
- references/migrations.md - Drizzle Kit configuration, CLI commands, migration workflow
- references/common-patterns.md - Soft delete, upsert, batch operations, full-text search, audit trails
1---2name: drizzle-orm-patterns3description: Provides comprehensive Drizzle ORM patterns for schema definition, CRUD operations, relations, queries, transactions, and migrations. Proactively use for any Drizzle ORM development including defining database schemas, writing type-safe queries, implementing relations, managing transactions, and setting up migrations with Drizzle Kit. Supports PostgreSQL, MySQL, SQLite, MSSQL, and CockroachDB.4---5
6# Drizzle ORM Patterns
7
8## Overview
9
10Expert guide for building type-safe database applications with Drizzle ORM. Covers schema definition, relations, queries, transactions, and migrations for all supported databases.
11
12## When to Use
13
14- Defining database schemas with tables, columns, and constraints
15- Creating relations between tables (one-to-one, one-to-many, many-to-many)
16- Writing type-safe CRUD queries
17- Implementing complex joins and aggregations
18- Managing database transactions with rollback
19- Setting up migrations with Drizzle Kit
20- Working with PostgreSQL, MySQL, SQLite, MSSQL, or CockroachDB
21
22## Quick Reference
23
24| Database | Table Function | Import |
25|----------|---------------|--------|
26| PostgreSQL | `pgTable()` | `drizzle-orm/pg-core` |
27| MySQL | `mysqlTable()` | `drizzle-orm/mysql-core` |
28| SQLite | `sqliteTable()` | `drizzle-orm/sqlite-core` |
29| MSSQL | `mssqlTable()` | `drizzle-orm/mssql-core` |
30
31| Operation | Method | Example |
32|-----------|--------|---------|
33| Insert | `db.insert()` | `db.insert(users).values({...})` |
34| Select | `db.select()` | `db.select().from(users).where(eq(...))` |
35| Update | `db.update()` | `db.update(users).set({...}).where(...)` |
36| Delete | `db.delete()` | `db.delete(users).where(...)` |
37| Transaction | `db.transaction()` | `db.transaction(async (tx) => {...})` |
38
39## Instructions
40
411. **Identify your database dialect** - Choose PostgreSQL, MySQL, SQLite, MSSQL, or CockroachDB
422. **Define your schema** - Use the appropriate table function (pgTable, mysqlTable, etc.)
433. **Set up relations** - Define relations using `relations()` or `defineRelations()`
444. **Initialize the database client** - Create your Drizzle client with proper credentials
455. **Write queries** - Use the query builder for type-safe CRUD operations
466. **Handle transactions** - Wrap multi-step operations in transactions when needed
477. **Set up migrations** - Configure Drizzle Kit for schema management
48
49## Examples
50
51### Example 1: Basic Schema and Query
52
53```typescript
54import { pgTable, serial, text } from 'drizzle-orm/pg-core';
55import { drizzle } from 'drizzle-orm/node-postgres';
56import { eq } from 'drizzle-orm';
57
58export const users = pgTable('users', {
59 id: serial('id').primaryKey(),
60 name: text('name').notNull(),
61 email: text('email').notNull().unique(),
62});
63
64const db = drizzle(process.env.DATABASE_URL);
65
66const [user] = await db.select().from(users).where(eq(users.id, 1));
67```
68
69### Example 2: CRUD Operations
70
71```typescript
72import { eq } from 'drizzle-orm';
73
74// Insert
75const [newUser] = await db.insert(users).values({
76 name: 'John',
77 email: 'john@example.com',
78}).returning();
79
80// Update
81await db.update(users)
82 .set({ name: 'John Updated' })
83 .where(eq(users.id, 1));
84
85// Delete
86await db.delete(users).where(eq(users.id, 1));
87```
88
89### Example 3: Transaction with Rollback
90
91```typescript
92await db.transaction(async (tx) => {
93 const [from] = await tx.select().from(accounts)
94 .where(eq(accounts.userId, fromId));
95
96 if (from.balance < amount) {
97 tx.rollback();
98 }
99
100 await tx.update(accounts)
101 .set({ balance: sql`${accounts.balance} - ${amount}` })
102 .where(eq(accounts.userId, fromId));
103});
104```
105
106See [references/transactions.md](references/transactions.md) for advanced transaction patterns.
107
108## Best Practices
109
1101. **Type Safety**: Always use TypeScript and leverage `$inferInsert` / `$inferSelect`
1112. **Relations**: Define relations using the relations() API for nested queries
1123. **Transactions**: Use transactions for multi-step operations that must succeed together
1134. **Migrations**: Use `generate` + `migrate` in production, `push` for development
1145. **Indexes**: Add indexes on frequently queried columns and foreign keys
1156. **Soft Deletes**: Use `deletedAt` timestamp instead of hard deletes when possible
1167. **Pagination**: Use cursor-based pagination for large datasets
1178. **Query Optimization**: Use `.limit()` and `.where()` to fetch only needed data
118
119## Constraints and Warnings
120
121- **Foreign Key Constraints**: Always define references using arrow functions `() => table.column` to avoid circular dependency issues
122- **Transaction Rollback**: Calling `tx.rollback()` throws an exception - use try/catch if needed
123- **Returning Clauses**: Not all databases support `.returning()` - check your dialect compatibility
124- **Batch Operations**: Large batch inserts may hit database limits - chunk into smaller batches
125- **Migrations in Production**: Always test migrations in staging before applying to production
126
127## References
128
129### Core Concepts
130- **[references/schema-definition.md](references/schema-definition.md)** - Complete schema definition for all databases (PostgreSQL, MySQL, SQLite), column types, indexes, and constraints
131- **[references/relations.md](references/relations.md)** - One-to-one, one-to-many, many-to-many relations with v1 and v2 syntax
132- **[references/queries-joins-aggregations.md](references/queries-joins-aggregations.md)** - CRUD operations, query operators, joins, aggregations, and pagination
133
134### Advanced Topics
135- **[references/transactions.md](references/transactions.md)** - Transaction patterns, rollback handling, nested transactions
136- **[references/migrations.md](references/migrations.md)** - Drizzle Kit configuration, CLI commands, migration workflow
137- **[references/common-patterns.md](references/common-patterns.md)** - Soft delete, upsert, batch operations, full-text search, audit trails