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 執行 `npm installdrizzle-orm` 來安裝核心 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 已針對無伺服器及邊緣執行環境的效能進行了優化。
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]





首頁
