drizzle-orm
bobmatnyc/claude-mpm-skills
一款适用于 TypeScript 的类型安全 SQL ORM,且无运行时开销
...展开全部关于drizzle-orm
Drizzle ORM 是一个现代化的、以 TypeScript 为核心的对象关系映射(ORM)库,旨在提供与 SQL 数据库的类型安全交互,同时保持零运行时开销。 它通过提供编译时类型检查以及开发者可在 TypeScript 中直接使用的类 SQL 语法,解决了在处理关系型数据库时常见的运行时错误和类型不匹配问题。这使得数据库操作更加可预测,并降低了在无服务器或边缘运行时环境中出现错误的可能性——在这些环境中,效率和最小化依赖至关重要。
该 ORM 提供了多项关键功能和能力。它支持多种数据库,包括 PostgreSQL、MySQL 和 SQLite,允许开发者根据项目需求选择合适的驱动程序。Drizzle ORM 提供了一个灵活的模式定义系统,其中多种列类型直接映射到 TypeScript 类型,从而为查询、插入和更新操作提供了强类型支持。 它还包含用于定义表间关系(如一对多关系)的功能,并支持对 SELECT 和 INSERT 操作进行类型推断。此外,Drizzle Kit 可用于数据库迁移,从而更轻松地管理随时间推移的数据库模式变更。其零依赖设计确保了在项目中的轻量级集成,并在资源受限的环境中实现最佳性能。
目标用户包括开发与 SQL 数据库交互、且需要强类型安全性和可预测行为的 TypeScript 开发者。 Drizzle ORM 对于开发无服务器应用程序、边缘函数或那些重视性能和最小运行时开销的项目尤为有用。它适用于从简单的 CRUD 应用程序到具有关系型数据模型和高级查询模式的更复杂系统等多种场景,在利用 TypeScript 类型系统的同时,为数据库交互提供了一种可靠且易于维护的方法。
常见问题
如何安装和配置 Drizzle ORM?
您可以通过 npm 安装核心 ORM:`npm installdrizzle-orm`,然后安装适用于您数据库的相应驱动程序,例如 PostgreSQL 使用的 `pg` 或 MySQL 使用的 `mysql2`。若需进行数据库迁移,请将 `drizzle-kit` 作为开发依赖项进行安装。
Drizzle ORM 支持哪些数据库?
Drizzle ORM 通过各自的数据库驱动程序支持 PostgreSQL、MySQL 和 SQLite。
Drizzle ORM 会增加运行时开销吗?
不会,Drizzle ORM 的设计旨在实现零运行时开销,它依赖于编译时类型检查来确保安全性和正确性。
我可以定义表之间的关系吗?
可以,Drizzle ORM 支持定义“一对多”等关系,允许您在 TypeScript 中安全地建模关系型数据。
Drizzle ORM 适合无服务器或边缘计算环境吗?
是的,由于其零依赖设计和高效的查询处理机制,它针对无服务器和边缘运行时的性能进行了优化。
Drizzle ORM
Modern TypeScript-first ORM with zero dependencies, compile-time type safety, and SQL-like syntax. Optimized for edge runtimes and serverless environments.
Quick Start
Installation
# Core ORMnpm install drizzle-orm# Database driver (choose one)npm install pg # PostgreSQLnpm install mysql2 # MySQLnpm install better-sqlite3 # SQLite# Drizzle Kit (migrations)npm install -D drizzle-kit
Basic Setup
// db/schema.tsimport { pgTable, serial, text, timestamp } from 'drizzle-orm/pg-core';export const users = pgTable('users', { id: serial('id').primaryKey(), email: text('email').notNull().unique(), name: text('name').notNull(), createdAt: timestamp('created_at').defaultNow(),});// db/client.tsimport { drizzle } from 'drizzle-orm/node-postgres';import { Pool } from 'pg';import * as schema from './schema';const pool = new Pool({ connectionString: process.env.DATABASE_URL });export const db = drizzle(pool, { schema });
First Query
import { db } from './db/client';import { users } from './db/schema';import { eq } from 'drizzle-orm';// Insertconst newUser = await db.insert(users).values({ email: '[email protected]', name: 'John Doe',}).returning();// Selectconst allUsers = await db.select().from(users);// Whereconst user = await db.select().from(users).where(eq(users.id, 1));// Updateawait db.update(users).set({ name: 'Jane Doe' }).where(eq(users.id, 1));// Deleteawait db.delete(users).where(eq(users.id, 1));
Schema Definition
Column Types Reference
| PostgreSQL | MySQL | SQLite | TypeScript |
|---|---|---|---|
serial() | serial() | integer() | number |
text() | text() | text() | string |
integer() | int() | integer() | number |
boolean() | boolean() | integer() | boolean |
timestamp() | datetime() | integer() | Date |
json() | json() | text() | unknown |
uuid() | varchar(36) | text() | string |
Common Schema Patterns
import { pgTable, serial, text, varchar, integer, boolean, timestamp, json, unique } from 'drizzle-orm/pg-core';export const users = pgTable('users', { id: serial('id').primaryKey(), email: varchar('email', { length: 255 }).notNull().unique(), passwordHash: varchar('password_hash', { length: 255 }).notNull(), role: text('role', { enum: ['admin', 'user', 'guest'] }).default('user'), metadata: json('metadata').$type<{ theme: string; locale: string }>(), isActive: boolean('is_active').default(true), createdAt: timestamp('created_at').defaultNow().notNull(), updatedAt: timestamp('updated_at').defaultNow().notNull(),}, (table) => ({ emailIdx: unique('email_unique_idx').on(table.email),}));// Infer TypeScript typestype User = typeof users.$inferSelect;type NewUser = typeof users.$inferInsert;
Relations
One-to-Many
import { pgTable, serial, text, integer } from 'drizzle-orm/pg-core';import { relations } from 'drizzle-orm';export const authors = pgTable('authors', { id: serial('id').primaryKey(), name: text('name').notNull(),});export const posts = pgTable('posts', { id: serial('id').primaryKey(), title: text('title').notNull(), authorId: integer('author_id').notNull().references(() => authors.id),});export const authorsRelations = relations(authors, ({ many }) => ({ posts: many(posts),}));export const postsRelations = relations(posts, ({ one }) => ({ author: one(authors, { fields: [posts.authorId], references: [authors.id], }),}));// Query with relationsconst authorsWithPosts = await db.query.authors.findMany({ with: { posts: true },});
Many-to-Many
export const users = pgTable('users', { id: serial('id').primaryKey(), name: text('name').notNull(),});export const groups = pgTable('groups', { id: serial('id').primaryKey(), name: text('name').notNull(),});export const usersToGroups = pgTable('users_to_groups', { userId: integer('user_id').notNull().references(() => users.id), groupId: integer('group_id').notNull().references(() => groups.id),}, (table) => ({ pk: primaryKey({ columns: [table.userId, table.groupId] }),}));export const usersRelations = relations(users, ({ many }) => ({ groups: many(usersToGroups),}));export const groupsRelations = relations(groups, ({ many }) => ({ users: many(usersToGroups),}));export const usersToGroupsRelations = relations(usersToGroups, ({ one }) => ({ user: one(users, { fields: [usersToGroups.userId], references: [users.id] }), group: one(groups, { fields: [usersToGroups.groupId], references: [groups.id] }),}));
Queries
Filtering
import { eq, ne, gt, gte, lt, lte, like, ilike, inArray, isNull, isNotNull, and, or, between } from 'drizzle-orm';// Equalityawait db.select().from(users).where(eq(users.email, '[email protected]'));// Comparisonawait db.select().from(users).where(gt(users.id, 10));// Pattern matchingawait db.select().from(users).where(like(users.name, '%John%'));// Multiple conditionsawait db.select().from(users).where( and( eq(users.role, 'admin'), gt(users.createdAt, new Date('2024-01-01')) ));// IN clauseawait db.select().from(users).where(inArray(users.id, [1, 2, 3]));// NULL checksawait db.select().from(users).where(isNull(users.deletedAt));
Joins
import { eq } from 'drizzle-orm';// Inner joinconst result = await db .select({ user: users, post: posts, }) .from(users) .innerJoin(posts, eq(users.id, posts.authorId));// Left joinconst result = await db .select({ user: users, post: posts, }) .from(users) .leftJoin(posts, eq(users.id, posts.authorId));// Multiple joins with aggregationimport { count, sql } from 'drizzle-orm';const result = await db .select({ authorName: authors.name, postCount: count(posts.id), }) .from(authors) .leftJoin(posts, eq(authors.id, posts.authorId)) .groupBy(authors.id);
Pagination & Sorting
import { desc, asc } from 'drizzle-orm';// Order byawait db.select().from(users).orderBy(desc(users.createdAt));// Limit & offsetawait db.select().from(users).limit(10).offset(20);// Pagination helperfunction paginate(page: number, pageSize: number = 10) { return db.select().from(users) .limit(pageSize) .offset(page * pageSize);}
Transactions
// Auto-rollback on errorawait db.transaction(async (tx) => { await tx.insert(users).values({ email: '[email protected]', name: 'John' }); await tx.insert(posts).values({ title: 'First Post', authorId: 1 }); // If any query fails, entire transaction rolls back});// Manual controlconst tx = db.transaction(async (tx) => { const user = await tx.insert(users).values({ ... }).returning(); if (!user) { tx.rollback(); return; } await tx.insert(posts).values({ authorId: user.id });});
Migrations
Drizzle Kit Configuration
// drizzle.config.tsimport type { Config } from 'drizzle-kit';export default { schema: './db/schema.ts', out: './drizzle', dialect: 'postgresql', dbCredentials: { url: process.env.DATABASE_URL!, },} satisfies Config;
Migration Workflow
# Generate migrationnpx drizzle-kit generate# View SQLcat drizzle/0000_migration.sql# Apply migrationnpx drizzle-kit migrate# Introspect existing databasenpx drizzle-kit introspect# Drizzle Studio (database GUI)npx drizzle-kit studio
Example Migration
-- drizzle/0000_initial.sqlCREATE TABLE IF NOT EXISTS "users" ( "id" serial PRIMARY KEY NOT NULL, "email" varchar(255) NOT NULL, "name" text NOT NULL, "created_at" timestamp DEFAULT now() NOT NULL, CONSTRAINT "users_email_unique" UNIQUE("email"));
Navigation
Detailed References
🏗️ Advanced Schemas - Custom types, composite keys, indexes, constraints, multi-tenant patterns. Load when designing complex database schemas.
🔍 Query Patterns - Subqueries, CTEs, raw SQL, prepared statements, batch operations. Load when optimizing queries or handling complex filtering.
⚡ Performance - Connection pooling, query optimization, N+1 prevention, prepared statements, edge runtime integration. Load when scaling or optimizing database performance.
🔄 vs Prisma - Feature comparison, migration guide, when to choose Drizzle over Prisma. Load when evaluating ORMs or migrating from Prisma.
Red Flags
Stop and reconsider if:
- Using
anyorunknownfor JSON columns without type annotation - Building raw SQL strings without using
sqltemplate (SQL injection risk) - Not using transactions for multi-step data modifications
- Fetching all rows without pagination in production queries
- Missing indexes on foreign keys or frequently queried columns
- Using
select()without specifying columns for large tables
Performance Benefits vs Prisma
| Metric | Drizzle | Prisma |
|---|---|---|
| Bundle Size | ~35KB | ~230KB |
| Cold Start | ~10ms | ~250ms |
| Query Speed | Baseline | ~2-3x slower |
| Memory | ~10MB | ~50MB |
| Type Generation | Runtime inference | Build-time generation |
Integration
- typescript-core: Type-safe schema inference with
satisfies - nextjs-core: Server Actions, Route Handlers, Middleware integration
- Database Migration: Safe schema evolution patterns
Related Skills
When using Drizzle, these skills enhance your workflow:
- prisma: Alternative ORM comparison: Drizzle vs Prisma trade-offs
- typescript: Advanced TypeScript patterns for type-safe queries
- nextjs: Drizzle with Next.js Server Actions and API routes
- sqlalchemy: SQLAlchemy patterns for Python developers learning Drizzle
[Full documentation available in these skills if deployed in your bundle]





首页
