01. Drizzle ORM 소개

2026년 2월 16일 수정됨

📋 개요

ORM(Object-Relational Mapping)은 데이터베이스 테이블을 코드의 객체로 매핑하여, SQL을 직접 작성하지 않고도 데이터베이스를 조작할 수 있게 해주는 도구입니다.

📋 목차

ORM이란?

ORM(Object-Relational Mapping)은 데이터베이스 테이블을 코드의 객체로 매핑하여, SQL을 직접 작성하지 않고도 데이터베이스를 조작할 수 있게 해주는 도구입니다.

┌─────────────────────────────────────────────────────────┐
│  TypeScript 코드        ←→  ORM  ←→  PostgreSQL        │
│  db.select().from(users)     →     SELECT * FROM users  │
└─────────────────────────────────────────────────────────┘

Drizzle ORM 특징

특징설명
타입 안전성스키마에서 TypeScript 타입 자동 추론
SQL-like 문법SQL과 유사한 API로 학습 곡선 낮음
경량런타임 의존성 최소화, 빠른 실행 속도
Serverless 최적화Edge 환경에서도 동작

프로젝트 구조

packages/schema/          # 공유 스키마 패키지
├── src/
│   ├── schema/           # 테이블 정의
│   │   ├── users.ts      # 사용자 테이블
│   │   ├── stocks.ts     # 주식 테이블
│   │   └── index.ts      # 스키마 내보내기
│   └── index.ts          # 메인 진입점
└── drizzle.config.ts     # Drizzle Kit 설정

구조 설명:

  • packages/schema/: 모노레포에서 FE/BE가 공유하는 스키마 패키지입니다.
  • schema/: 각 도메인별 테이블 정의를 분리하여 관리합니다.
  • drizzle.config.ts: 마이그레이션, DB 연결 등 Drizzle Kit 도구 설정 파일입니다.

데이터베이스 연결

// packages/schema/src/db.ts
import { drizzle } from 'drizzle-orm/postgres-js';
import postgres from 'postgres';
import * as schema from './schema';
 
// 1. PostgreSQL 클라이언트 생성
const client = postgres(process.env.DATABASE_URL!, {
  max: 10,              // 최대 연결 수
  idle_timeout: 20,     // 유휴 연결 타임아웃 (초)
  connect_timeout: 10,  // 연결 타임아웃 (초)
});
 
// 2. Drizzle 인스턴스 생성
export const db = drizzle(client, { schema });

코드 설명:

  • postgres(DATABASE_URL): postgres 라이브러리로 PostgreSQL에 연결합니다. 연결 풀 설정도 여기서 지정합니다.
  • max: 10: 동시에 유지할 수 있는 최대 DB 연결 수입니다. 서버 부하에 따라 조절합니다.
  • drizzle(client, { schema }): Drizzle 인스턴스를 생성합니다. schema를 전달하면 관계형 쿼리 API를 사용할 수 있습니다.
  • export const db: 이 인스턴스를 애플리케이션 전체에서 임포트하여 사용합니다.

첫 번째 스키마 정의

// packages/schema/src/schema/users.ts
import { pgTable, uuid, varchar, timestamp } from 'drizzle-orm/pg-core';
 
export const users = pgTable('users', {
  // uuid 타입의 기본키, 자동 생성
  id: uuid('id').primaryKey().defaultRandom(),
  
  // varchar(100) 타입, null 불가, 중복 불가
  email: varchar('email', { length: 100 }).notNull().unique(),
  
  // varchar(50) 타입, null 불가
  name: varchar('name', { length: 50 }).notNull(),
  
  // 생성 시간, 기본값: 현재 시간
  createdAt: timestamp('created_at').defaultNow().notNull(),
  
  // 수정 시간, 레코드 변경 시 자동 업데이트
  updatedAt: timestamp('updated_at').defaultNow().notNull(),
});

각 컬럼 설명:

  • uuid('id'): PostgreSQL의 UUID 타입입니다. defaultRandom()은 자동으로 고유 ID를 생성합니다.
  • varchar('email', { length: 100 }): 최대 100자 문자열입니다. unique()로 중복 이메일을 방지합니다.
  • timestamp('created_at'): 날짜/시간 타입입니다. defaultNow()는 INSERT 시 현재 시간을 자동 설정합니다.
  • .notNull(): NULL 값을 허용하지 않는 제약 조건입니다.

기본 조회 예제

import { db } from './db';
import { users } from './schema';
import { eq } from 'drizzle-orm';
 
// 모든 사용자 조회
const allUsers = await db.select().from(users);
 
// 특정 사용자 조회
const user = await db
  .select()
  .from(users)
  .where(eq(users.id, 'user-uuid-here'));

코드 설명:

  • db.select().from(users): SELECT * FROM users와 동일합니다. 모든 컬럼을 가져옵니다.
  • eq(users.id, 'user-uuid-here'): WHERE id = 'user-uuid-here' 조건입니다. eq는 equality(동등) 비교 연산자입니다.
  • where(): SQL의 WHERE 절에 해당하며, 여러 조건을 체이닝할 수 있습니다.

레퍼런스

다음 장: 02. 스키마 기초