옵션
집 Skill 웹 개발 drizzle-orm

런타임 오버헤드가 전혀 없는 TypeScript용 타입 안전 SQL ORM

...모든 것을 확장하십시오
70
업데이트 된 시간 2026년 6월 29일

소개 drizzle-orm

Drizzle ORM은 런타임 오버헤드를 전혀 발생시키지 않으면서 SQL 데이터베이스와 유형 안전한 상호 작용을 제공하도록 설계된, 현대적인 TypeScript 우선 객체-관계 매핑(ORM) 라이브러리입니다. 이 라이브러리는 컴파일 시점 타입 검사와 개발자가 TypeScript에서 직접 사용할 수 있는 SQL과 유사한 구문을 제공함으로써, 관계형 데이터베이스 작업 시 흔히 발생하는 런타임 오류 및 타입 불일치 문제를 해결합니다. 이를 통해 데이터베이스 작업의 예측 가능성을 높이고, 효율성과 의존성 최소화가 중요한 서버리스 또는 엣지 런타임 환경에서 버그 발생 가능성을 줄여줍니다.

이 ORM은 여러 가지 주요 기능과 성능을 제공합니다. PostgreSQL, MySQL, SQLite를 포함한 다양한 데이터베이스를 지원하므로 개발자는 프로젝트에 적합한 드라이버를 선택할 수 있습니다. Drizzle ORM은 다양한 열 유형을 TypeScript 유형에 직접 매핑하는 유연한 스키마 정의 시스템을 제공하여 쿼리, 삽입 및 업데이트에 대한 강력한 타입 지정을 가능하게 합니다. 또한 일대다 관계와 같은 테이블 간 관계를 정의하는 기능을 포함하며, SELECT 및 INSERT 연산 모두에 대한 타입 추론을 지원합니다. 아울러 Drizzle Kit을 마이그레이션에 활용할 수 있어, 시간이 지남에 따라 발생하는 데이터베이스 스키마 변경 사항을 보다 쉽게 관리할 수 있습니다. 의존성이 전혀 없는 설계 덕분에 프로젝트에 가볍게 통합할 수 있으며, 자원이 제한된 환경에서도 최적의 성능을 보장합니다.

주요 대상 사용자는 SQL 데이터베이스와 상호작용하며 강력한 타입 안전성과 예측 가능한 동작이 필요한 애플리케이션을 구축하는 TypeScript 개발자입니다. Drizzle ORM은 특히 서버리스 애플리케이션, 엣지 함수 또는 성능과 최소한의 런타임 오버헤드가 중요한 프로젝트를 개발하는 사용자에게 유용합니다. 간단한 CRUD 애플리케이션부터 관계형 데이터 모델과 고급 쿼리 패턴을 사용하는 더 복잡한 시스템에 이르기까지 다양한 시나리오에 적합하며, TypeScript의 타입 시스템을 활용하면서 데이터베이스 상호 작용에 대한 안정적이고 유지 관리가 용이한 접근 방식을 제공합니다.

자주 묻는 질문

Drizzle ORM은 어떻게 설치하고 설정하나요?

npm을 사용하여 `npm install drizzle-orm` 명령어로 핵심 ORM을 설치한 후, PostgreSQL용 `pg`나 MySQL용 `mysql2`와 같이 사용 중인 데이터베이스에 적합한 데이터베이스 드라이버를 설치하면 됩니다. 마이그레이션을 위해서는 `drizzle-kit`을 개발 의존성으로 설치하십시오.

Drizzle ORM은 어떤 데이터베이스와 호환되나요?

Drizzle ORM은 각 데이터베이스 드라이버를 통해 PostgreSQL, MySQL 및 SQLite를 지원합니다.

Drizzle ORM은 런타임 오버헤드를 발생시키나요?

아니요, Drizzle ORM은 런타임 오버헤드가 전혀 없도록 설계되었으며, 안전성과 정확성을 보장하기 위해 컴파일 시점의 타입 검사에 의존합니다.

테이블 간의 관계를 정의할 수 있나요?

네, Drizzle ORM은 일대다와 같은 관계 정의를 지원하므로, TypeScript에서 관계형 데이터를 안전하게 모델링할 수 있습니다.

Drizzle ORM은 서버리스 또는 엣지 환경에 적합한가요?

네, 의존성이 전혀 없는 설계와 효율적인 쿼리 처리 덕분에 서버리스 및 엣지 런타임 환경에서 성능이 최적화되어 있습니다.

GitHub에서 보기

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

PostgreSQLMySQLSQLiteTypeScript
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 any or unknown for JSON columns without type annotation
  • Building raw SQL strings without using sql template (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

MetricDrizzlePrisma
Bundle Size~35KB~230KB
Cold Start~10ms~250ms
Query SpeedBaseline~2-3x slower
Memory~10MB~50MB
Type GenerationRuntime inferenceBuild-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

복사 복사
빠른 설정: skill 폴더를 .claude/skills/로 복사하면 Claude가 해당 스킬을 자동으로 감지하여 사용합니다.

관련 스킬

github-code-search
업데이트 된 시간 2026년 6월 29일
clickhouse-io
업데이트 된 시간 2026년 6월 29일
prisma-client-api
업데이트 된 시간 2026년 6월 29일
coding-standards
업데이트 된 시간 2026년 6월 29일
OR