Drizzle ORM + SQLite로 가벼운 백엔드 만들기
데이터베이스 하면 PostgreSQL이나 MySQL을 떠올리지만, 소규모 서비스나 사이드 프로젝트에는SQLite가 훨씬 합리적입니다. 서버 설치도 필요 없고, 파일 하나가 곧 데이터베이스입니다. 여기에 Drizzle ORM을 결합하면 타입 안전한 쿼리와 깔끔한 스키마 관리까지 얻을 수 있습니다.
0원
DB 서버 비용
1파일
데이터베이스
완전
타입 안전성
향상
동시 읽기 (WAL)
1Drizzle ORM vs Prisma 비교
Node.js ORM 중 Prisma가 가장 인기 있지만, 번들 크기와 쿼리 엔진 때문에 서버리스나 경량 환경에서는 부담이 됩니다. Drizzle은 SQL에 가까운 문법으로 설계된 경량 ORM입니다.
| 항목 | Prisma | Drizzle ORM |
|---|---|---|
| 번들 크기 | ~2MB (쿼리 엔진 포함) | ~50KB |
| 쿼리 문법 | 독자적 API | SQL에 가까움 |
| 타입 추론 | 코드 생성 기반 | 네이티브 TypeScript |
| 마이그레이션 | 자동 생성 | 수동 + 자동 혼합 |
| SQLite 지원 | 지원 (제한적) | 완전 지원 |
| 학습 곡선 | 낮음 (직관적 API) | 보통 (SQL 지식 필요) |
SQL을 이미 알고 있다면 Drizzle이 자연스럽습니다
Drizzle의 쿼리 빌더는 SQL 문법과 거의 1:1로 대응됩니다.select().from(users).where(eq(users.id, 1))같은 코드가 SQL을 아는 사람에게는 바로 읽힙니다.
2프로덕션에서 SQLite를 쓰는 이유
"SQLite는 개발용 아닌가요?"라는 의문이 있을 수 있습니다. 하지만 SQLite는 전 세계에서 가장 많이 배포된 데이터베이스이며, 적절한 설정만 하면 프로덕션에서도 충분히 사용할 수 있습니다.
| SQLite가 적합한 경우 | PostgreSQL이 필요한 경우 |
|---|---|
| 단일 서버 운영 | 다중 서버에서 DB 공유 |
| 읽기 위주의 워크로드 | 동시 쓰기가 매우 많음 |
| 소규모 ~ 중규모 트래픽 | 대규모 트래픽 |
| 블로그, 포트폴리오, SaaS MVP | 복잡한 조인, 풀텍스트 검색 |
| DB 서버 비용 없음 | 고급 기능 (저장 프로시저, 네이티브 복제) |
SQLite 파일은 반드시 백업 스크립트를 설정하세요
SQLite는 파일 기반이므로 서버 장애 시 데이터가 손실될 수 있습니다. cron으로 정기 백업을 설정하거나, Litestream 같은 도구로 실시간 복제를 구성하는 것을 강력히 권장합니다.
3스키마 정의
Drizzle ORM은 TypeScript 코드로 스키마를 정의합니다. Prisma처럼 별도의 schema 파일이 아니라 일반 TypeScript 파일이라서 IDE 자동완성과 타입 체크가 바로 적용됩니다.
# 패키지 설치
npm install drizzle-orm better-sqlite3 npm install -D drizzle-kit @types/better-sqlite3
lib/db/schema.ts — 스키마 정의 예시
import { sqliteTable, text, integer } from "drizzle-orm/sqlite-core";
export const users = sqliteTable("users", {
id: text("id").primaryKey(),
email: text("email").notNull().unique(),
name: text("name").notNull(),
role: text("role").notNull().default("user"),
createdAt: integer("created_at", { mode: "timestamp" })
.notNull()
.$defaultFn(() => new Date()),
});
export const posts = sqliteTable("posts", {
id: integer("id").primaryKey({ autoIncrement: true }),
title: text("title").notNull(),
content: text("content").notNull(),
authorId: text("author_id")
.notNull()
.references(() => users.id),
publishedAt: integer("published_at", { mode: "timestamp" }),
});4마이그레이션
Drizzle Kit은 스키마 변경을 감지해서 SQL 마이그레이션 파일을 자동으로 생성합니다. Prisma의 prisma migrate와 비슷한 역할입니다.
drizzle.config.ts
import { defineConfig } from "drizzle-kit";
export default defineConfig({
schema: "./lib/db/schema.ts",
out: "./drizzle",
dialect: "sqlite",
dbCredentials: {
url: "./data/app.db",
},
});# 마이그레이션 명령어
# 마이그레이션 파일 생성 (스키마 변경 감지) npx drizzle-kit generate # 마이그레이션 적용 npx drizzle-kit migrate # 스키마를 DB에 직접 반영 (개발 중 빠른 적용) npx drizzle-kit push # Drizzle Studio로 DB 내용 확인 (GUI) npx drizzle-kit studio
개발 중에는 push, 프로덕션에는 generate + migrate
drizzle-kit push는 스키마를 DB에 직접 반영하므로 개발 중 빠르게 테스트할 때 좋습니다. 프로덕션에서는 반드시 마이그레이션 파일을 생성하고 적용하는 과정을 거쳐야 데이터 손실을 방지할 수 있습니다.
5시드 데이터
초기 데이터(관리자 계정, 기본 설정 등)를 넣기 위한 시드 스크립트를 만들어두면 새 환경 구축이나 테스트 DB 초기화가 편합니다.
scripts/seed.ts
import { db } from "../lib/db";
import { users } from "../lib/db/schema";
async function seed() {
console.log("시드 데이터 삽입 시작...");
// 관리자 계정 생성
await db.insert(users).values({
id: "admin-001",
email: "admin@example.com",
name: "관리자",
role: "admin",
}).onConflictDoNothing();
console.log("시드 데이터 삽입 완료");
}
seed().catch(console.error);# 시드 실행 (tsx 사용)
# tsx로 TypeScript 직접 실행
npx tsx scripts/seed.ts
# package.json에 스크립트 추가
# "scripts": { "seed": "tsx scripts/seed.ts" }
npm run seed6WAL 모드로 동시 읽기 성능 확보
SQLite의 기본 저널 모드는 delete 모드로, 쓰기 중에는 읽기도 차단됩니다.WAL(Write-Ahead Logging) 모드를 활성화하면 쓰기 중에도 읽기가 가능해져 웹 서비스의 동시 접속 처리 능력이 크게 향상됩니다.
lib/db/index.ts — WAL 모드 활성화
import Database from "better-sqlite3";
import { drizzle } from "drizzle-orm/better-sqlite3";
import * as schema from "./schema";
const sqlite = new Database("./data/app.db");
// WAL 모드 활성화 (한 번만 실행하면 영구 적용)
sqlite.pragma("journal_mode = WAL");
// 추가 성능 최적화
sqlite.pragma("busy_timeout = 5000"); // 잠금 대기 5초
sqlite.pragma("synchronous = NORMAL"); // 성능과 안정성 균형
sqlite.pragma("foreign_keys = ON"); // 외래 키 활성화
export const db = drizzle(sqlite, { schema });| 설정 | 값 | 효과 |
|---|---|---|
| journal_mode | WAL | 쓰기 중 읽기 가능, 동시성 향상 |
| busy_timeout | 5000 | 잠금 시 5초간 재시도 |
| synchronous | NORMAL | WAL 모드에서 권장, 성능/안정성 균형 |
| foreign_keys | ON | 외래 키 제약 조건 활성화 |
WAL 모드에서 .db-wal, .db-shm 파일이 생깁니다
WAL 모드를 활성화하면 데이터베이스 파일 옆에 .db-wal과 .db-shm 파일이 생성됩니다. 백업할 때 이 파일들도 함께 복사해야 합니다. 그렇지 않으면 최근 변경 사항이 누락될 수 있습니다.
요약 체크리스트
Drizzle ORM + SQLite 핵심 요약
- ✓Drizzle ORM은 번들 크기가 작고 SQL에 가까운 직관적 문법을 제공한다
- ✓SQLite는 단일 서버, 읽기 위주 워크로드에서 PostgreSQL 대안이 된다
- ✓TypeScript 코드로 스키마를 정의하고 drizzle-kit으로 마이그레이션한다
- ✓시드 스크립트로 초기 데이터(관리자 계정 등)를 관리한다
- ✓WAL 모드를 활성화하여 동시 읽기 성능을 확보한다
- ✓SQLite 파일과 WAL 파일을 정기적으로 백업한다
본 글은 Drizzle ORM v0.35+ 및 better-sqlite3 기준으로 작성되었습니다. SQLite의 동시 쓰기 제한은 트래픽 규모에 따라 병목이 될 수 있으므로, 서비스 성장에 따라 PostgreSQL 마이그레이션을 고려하시기 바랍니다. 본 콘텐츠의 비상업적 공유는 자유이나, 상업적 이용 시 문의 페이지를 통해 연락 바랍니다.
웹 서비스 백엔드 구축이 필요하신가요?
Treeru는 Drizzle ORM, SQLite, Better Auth를 활용한 경량 백엔드부터 PostgreSQL 기반 대규모 시스템까지 구축해 드립니다.
백엔드 구축 상담 신청댓글
(4개)로그인하면 댓글을 작성할 수 있습니다.
마이그레이션 과정이 Prisma보다 수동적이지만, 그만큼 자유도가 높다는 장점이 있네요. 시드 스크립트 예제도 유용했습니다.
Drizzle의 타입 추론이 정말 좋습니다. 스키마에서 정의한 타입이 쿼리 결과까지 자동으로 추론되니까 런타임 에러가 거의 없어졌어요.
PostgreSQL 서버 유지비가 부담스러웠는데, SQLite + WAL 모드로 바꾸니까 충분히 잘 돌아갑니다. 소규모 서비스에는 최고의 조합이에요.
관련 글
© 2026 TreeRU. All rights reserved.
본 콘텐츠의 저작권은 TreeRU에 있으며, 출처를 밝히지 않은 무단 전재 및 재배포를 금합니다. 인용 시 출처(treeru.com)를 반드시 명시해 주세요.