본문 바로가기
Backend2026년 5월 7일6분 읽기

Drizzle 2.0 — Prisma에서 옮긴 6개월 후일담, 무엇이 좋아졌고 무엇이 어색했나

YS
김영삼
조회 324
Drizzle 2.0 — Prisma에서 옮긴 6개월 후일담, 무엇이 좋아졌고 무엇이 어색했나

핵심 요약

2025년 11월 회사 메인 서비스(API 300개·테이블 120개)의 ORM을 Prisma 6에서 Drizzle 2.0으로 옮겼다. 6개월 운영 결과: 빌드 -38%, 콜드 스타트 -52%, 메모리 -33%. 하지만 "관계 로딩"에서 Prisma가 그리워지는 순간이 있다.

1. 옮긴 동기 — 무엇이 문제였나

  • Prisma Client 번들 크기: 8.7MB (engine 포함). Vercel/Cloudflare edge에서 문제.
  • 쿼리 엔진 콜드 스타트: Lambda 환경에서 평균 320ms 추가
  • raw SQL이 답답함: 복잡한 윈도우 함수·CTE를 Prisma 추상화로 표현 불가
  • 마이그레이션 충돌: 팀원 6명, 매주 conflict 한 번씩

2. 스키마 비교

Prisma는 자체 DSL, Drizzle은 TypeScript 코드.

// Prisma
model User {
  id      Int    @id @default(autoincrement())
  email   String @unique
  posts   Post[]
}

// Drizzle
import { pgTable, serial, text } from 'drizzle-orm/pg-core'
export const users = pgTable('users', {
  id: serial('id').primaryKey(),
  email: text('email').notNull().unique(),
})
export const usersRelations = relations(users, ({ many }) => ({
  posts: many(posts),
}))

Drizzle은 코드라서 조건부 컬럼·동적 테이블·고급 타입 합성이 자유롭다. 대신 처음엔 번잡하게 느껴진다.

2. 쿼리 — SQL에 가까움

// Prisma — 추상적
const posts = await prisma.post.findMany({
  where: { author: { email: 'kim@x.com' } },
  include: { tags: true },
  orderBy: { createdAt: 'desc' },
})

// Drizzle — SQL스러움
const posts = await db
  .select()
  .from(postsTable)
  .innerJoin(users, eq(postsTable.authorId, users.id))
  .where(eq(users.email, 'kim@x.com'))
  .orderBy(desc(postsTable.createdAt))

장점: SQL 그대로라 EXPLAIN ANALYZE 결과 예측 가능. 단점: 관계 로딩이 한 줄로 끝나지 않는다.

3. 실측 — 6개월 평균

지표Prisma 6Drizzle 2.0변화
node_modules 크기286MB62MB-78%
tsc 빌드 시간48s30s-38%
Lambda 콜드 스타트1,180ms560ms-52%
RAM (idle)168MB112MB-33%
단순 select P504.2ms3.9ms-7%
5개 join P5014ms11ms-21%
insert + return P506.1ms5.8ms-5%

가장 큰 이득은 콜드 스타트. Edge·FaaS에서 큰 차이.

4. 마이그레이션 함정 7가지

① N+1 문제 표면화

Prisma의 include는 N+1을 자동으로 한 쿼리로 묶지 않고 IN 절로 처리. Drizzle은 그냥 N+1이 나옴. with + relations로 명시.

const result = await db.query.posts.findMany({
  with: { author: true, tags: true },
})  // Drizzle도 한 번에 처리 가능

② JSON 컬럼 타입

Prisma는 Json = any, Drizzle은 제네릭으로 강타입.

metadata: jsonb('metadata').$type<{ tags: string[]; views: number }>()

③ 트랜잭션 격리수준

Prisma는 옵션 명시. Drizzle은 db.transaction(async tx => { ... }, { isolationLevel: 'serializable' }).

④ 마이그레이션 도구

drizzle-kit이 Prisma migrate보다 가벼움. 다만 충돌 해결은 수동. 팀 규약 필수.

⑤ 시드 데이터

Prisma의 prisma db seed 같은 표준이 없다. 자체 스크립트 작성.

⑥ Studio

Drizzle Studio가 Prisma Studio보다 가볍지만 기능은 80%. 데이터 편집 UX는 Prisma가 우위.

⑦ 에코시스템

NestJS·tRPC·Auth.js 통합 예시는 Prisma가 압도적으로 많음. Drizzle은 직접 wire-up.

5. 언제 Prisma를 그대로 두는 게 낫나

  • 팀이 SQL을 별로 안 쓰는 풀스택 신입 위주
  • Schema-driven 워크플로(스키마 → 마이그레이션 → 타입)에 만족
  • Edge/FaaS 비중이 낮음
  • Prisma Pulse·Accelerate 같은 부가 기능 이미 활용

6. 도입 순서 권장

  1. 새 마이크로서비스 1개를 Drizzle로 시작 (학습)
  2. 관계 모델 패턴이 잡힌 뒤 기존 서비스 1개 변환
  3. 드릴 다운: 가장 트래픽 큰 엔드포인트 10개 EXPLAIN으로 회귀 검증
  4. 전체 마이그레이션은 2~3개월 잡고, 신·구 ORM 공존 기간 둠

안티패턴

  • "Drizzle이 빠르다고 들어서" — 콜드 스타트가 문제 아닌 환경에선 차이 미미
  • "한 번에 다 옮긴다" — 6개월 잡고 점진 권장
  • "raw SQL만 쓰자" — Drizzle 추상화의 타입 안전성을 다 버림

참고

  • orm.drizzle.team — relational queries
  • github.com/drizzle-team/drizzle-orm/releases — 2.0 변경점

댓글 0

아직 댓글이 없습니다.
Ctrl+Enter로 등록