drizzle-orm
bobmatnyc/claude-mpm-skills
実行時のオーバーヘッドがゼロの、TypeScript 向け型安全な SQL ORM
...すべて拡張します概要drizzle-orm
Drizzle ORMは、実行時のオーバーヘッドをゼロに抑えつつ、SQLデータベースとの型安全なやり取りを実現するように設計された、TypeScriptを第一に考えた最新のオブジェクトリレーショナルマッピング(ORM)ライブラリです。 リレーショナルデータベースを扱う際に発生しがちな実行時エラーや型不一致の問題を、コンパイル時の型チェックと、開発者が TypeScript 内で直接使用できる SQL 風の構文を提供することで解決します。これにより、データベース操作の予測可能性が高まり、効率性と依存関係の最小化が重要なサーバーレスやエッジランタイム環境におけるバグの発生確率が低減されます。
このORMは、いくつかの重要な機能と能力を備えています。PostgreSQL、MySQL、SQLiteを含む複数のデータベースをサポートしており、開発者はプロジェクトに適したドライバーを選択できます。Drizzle ORMは、さまざまな列型がTypeScriptの型に直接マッピングされる柔軟なスキーマ定義システムを提供し、クエリ、挿入、更新における強力な型付けを可能にします。 また、1対多の関係など、テーブル間の関係を定義する機能も備えており、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は「1対多」などの関係の定義をサポートしており、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]
drizzle-ormをインストール
スキルファイルをダウンロードし、.claude/skills/ ディレクトリに解凍してください。
ZIPをダウンロードリポジトリをクローンし、スキルファイルをプロジェクトにコピーしてください。
git clone https://github.com/bobmatnyc/claude-mpm-skills/blob/main/toolchains/typescript/data/drizzle/SKILL.md # Copy SKILL.md to your .claude/skills/ directory
コピー





家
