๐ก ๊ธฐ๋ณธ ์์ฑ
๐ ๊ฐ์
DB ์คํค๋ง๋ฅผ ์์ ํ๊ฒ ๋ณ๊ฒฝํ๊ณ ์ ํํ๋ ์ํฌํ๋ก์ฐ์ ๋๋ค. ํ ๋จ์ ํ์ ๊ณผ ๋ฐฐํฌ ์๋๋ฆฌ์ค๋ฅผ ๋ค๋ฃน๋๋ค.
๐ ๋ชฉ์ฐจ
- โ๏ธ 1. Drizzle Config ์ค์ (์ต์ ์์ธ)
- ๐ ๏ธ 2. ํต์ฌ ๋ช ๋ น์ด ์์ธ ๊ฐ์ด๋
- ๐จ 3. ๋ฌธ์ ํด๊ฒฐ (Troubleshooting)
- ๐ 4. ๋ฐฐํฌ ์ ๋ต (Production Deployment)
- ๐ ๋ ํผ๋ฐ์ค
DB ์คํค๋ง๋ฅผ ์์ ํ๊ฒ ๋ณ๊ฒฝํ๊ณ ์ ํํ๋ "์ค๋ฌด ์ํฌํ๋ก์ฐ" ์
๋๋ค. ๋จ์ํ pushํ๋ ๊ฒ์ ๋์ด, ํ ๋จ์ ํ์
๊ณผ ๋ฐฐํฌ ์๋๋ฆฌ์ค๋ฅผ ๋ค๋ฃน๋๋ค.
โ๏ธ 1. Drizzle Config ์ค์ (์ต์ ์์ธ)
drizzle.config.ts ํ์ผ์ ๋ง์ด๊ทธ๋ ์ด์
๋๊ตฌ์ ๊ด์ ํ์
๋๋ค.
import { defineConfig } from 'drizzle-kit';
export default defineConfig({
dialect: 'postgresql', // 'mysql' | 'sqlite'
schema: './src/db/schema', // ์คํค๋ง ํ์ผ ์์น (๊ธ๋ก๋ธ ํจํด ๊ฐ๋ฅ 'src/**/*.schema.ts')
out: './drizzle', // ๋ง์ด๊ทธ๋ ์ด์
ํ์ผ(.sql) ์์ฑ ์์น
// DB ์ฐ๊ฒฐ ์ ๋ณด (๋ง์ด๊ทธ๋ ์ด์
์คํ์ฉ)
dbCredentials: {
url: process.env.DATABASE_URL!,
},
// โญ๏ธ ์ค์ ์ต์
๋ค
verbose: true, // ํฐ๋ฏธ๋์ ์คํ๋๋ SQL ์ถ๋ ฅ
strict: true, // ๋ฐ์ดํฐ ์์ค ๊ฒฝ๊ณ ๋ฌด์ ๋ถ๊ฐ (์์ ์ฅ์น)
tablesFilter: ['!private_*'], // ํน์ ํ
์ด๋ธ ๋ฌด์ (์: Supabase ๋ด๋ถ ํ
์ด๋ธ)
});๐ ๏ธ 2. ํต์ฌ ๋ช ๋ น์ด ์์ธ ๊ฐ์ด๋
generate (์ปค๋ฐ ๋ง๋ค๊ธฐ)
์คํค๋ง ๋ณ๊ฒฝ ์ฌํญ์ ๊ฐ์งํด์ .sql ํ์ผ์ ๋ง๋ญ๋๋ค. ๊ฐ์ฅ ๋ง์ด ์๋๋ค.
npx drizzle-kit generate
# โญ๏ธ ์๋ณํ๊ธฐ ์ฝ๊ฒ ์ด๋ฆ ๋ถ์ด๊ธฐ (์ถ์ฒ)
npx drizzle-kit generate --name add_user_phone
# -> drizzle/0001_add_user_phone.sql ์์ฑ๋จmigrate (์ปค๋ฐ ๋ฐ์ํ๊ธฐ)
์์ฑ๋ .sql ํ์ผ๋ค์ ์ค์ DB์ ์คํํฉ๋๋ค.
npx drizzle-kit migratecustom (์๋ SQL ์์ฑ)
Drizzle ORM ์คํค๋ง๋ก ํํ ๋ชปํ๋ ๊ฒ๋ค(Trigger, Stored Procedure ๋ฑ)์ ๋ง๋ค ๋ ์ฌ์ฉํฉ๋๋ค.
# ๋น ๋ง์ด๊ทธ๋ ์ด์
ํ์ผ ์์ฑ
npx drizzle-kit generate --custom --name create_audit_trigger์์ฑ๋ ๋น xxxx_create_audit_trigger.sql ํ์ผ์ ์ง์ SQL์ ์์ฑํ๋ฉด, ๋์ค์ migrate ํ ๋ ๊ฐ์ด ์คํ๋ฉ๋๋ค.
๐จ 3. ๋ฌธ์ ํด๊ฒฐ (Troubleshooting)
์ํฉ 1: Drift (ํ๋ฅ) ๐
"๋๊ฐ ๋ชฐ๋ DB๋ฅผ ์์ ํ์ด์!"
Drizzle ์คํค๋ง์ ์ค์ DB ์ํ๊ฐ ์ ๋ง์ ๋ ๋ฐ์ํฉ๋๋ค. (์: ๋๊ตฐ๊ฐ Supabase ๋์๋ณด๋์์ ์ง์ ์ปฌ๋ผ ์ถ๊ฐํจ)
- ์ง๋จ:
npx drizzle-kit check # -> ์ฐจ์ด์ ์ ๋ฆฌํฌํธ๋ก ๋ณด์ฌ์ค๋๋ค. - ํด๊ฒฐ A (์ฝ๋ ๊ธฐ์ค ๋๊ธฐํ):
๋ค์pushํ๊ฑฐ๋generateํด์ DB๋ฅผ ๋ด ์ฝ๋์ ๋ง์ถฅ๋๋ค. (DB ๋ณ๊ฒฝ์ฌํญ ๋ฎ์ด์) - ํด๊ฒฐ B (DB ๊ธฐ์ค ๋๊ธฐํ):
introspect(๋๋pull) ๋ช ๋ น์ด๋ก DB ์ํ๋ฅผ ์คํค๋ง ํ์ผ๋ก ์ญ์์ฑํฉ๋๋ค.npx drizzle-kit pull
์ํฉ 2: ์ถฉ๋ (Conflicts) โ๏ธ
๋๋ฃ A์ B๊ฐ ๋์์ ๋ง์ด๊ทธ๋ ์ด์ ํ์ผ์ ๋ง๋ค์ด์ ์ปค๋ฐํ์ต๋๋ค.
0005_add_post.sql(A)0005_add_comment.sql(B)
์์ ๋ฒํธ๊ฐ ๊ฒน์ณค๋ค์!
ํด๊ฒฐ:
- ํ์ผ ์ด๋ฆ์ ์ซ์๋ฅผ ์์ ํ๊ฑฐ๋ (์๋)
- ๊ฐ์ฅ ์ต์ ์ค๋
์ท์ ์ญ์ ํ๊ณ ๋ค์
generateํฉ๋๋ค. - Drizzle Kit์ด ์์์ ์์๋ฅผ ์ฌ์กฐ์ ํ๊ธฐ๋ ํฉ๋๋ค. (๋ฒ์ ์ ๋๋ฉด์ ๋๋ํด์ง)
๐ 4. ๋ฐฐํฌ ์ ๋ต (Production Deployment)
์์ ํ ๋ฐฐํฌ ์นํธ์ํธ CheckList โ
- Schema Sync: ๋ก์ปฌ์์
drizzle-kit generate์๋ฃ ํ ์ปค๋ฐ. - Dry Run: ์ค์ ๋ฐฐํฌ ์ ํ ์คํธ DB์ ๋จผ์ ์ ์ฉํด๋ด.
- Backup: (์ด์ ํ๊ฒฝ) ๋ฐฐํฌ ์ง์ ์ค๋ ์ท/๋ฐฑ์ ํ์.
- Auto Migrate: ์๋ฒ ์์ ์ ์คํฌ๋ฆฝํธ๋ก ์๋ ์คํ.
NestJS ๋ฑ ์๋ฒ ์ฝ๋์์ ์๋ ์คํํ๊ธฐ:
// src/db/migrate.ts
import { migrate } from 'drizzle-orm/postgres-js/migrator';
import { db } from './index';
async function main() {
console.log('Migrating...');
// 'drizzle' ํด๋์ sql ํ์ผ๋ค์ ์ฝ์ด์ ์คํ
await migrate(db, { migrationsFolder: './drizzle' });
console.log('Done!');
}
main();์ฃผ์: ์๋ฒ ์ธ์คํด์ค๊ฐ ์ฌ๋ฌ ๊ฐ(PM2 ํด๋ฌ์คํฐ, K8s ํ๋ ๋ฑ)์ผ ๋, ๋์์
migrate๊ฐ ์คํ๋๋ฉด ๋ฝ(Lock) ๊ฑธ๋ฆฌ๊ฑฐ๋ ๊ผฌ์ผ ์ ์์ต๋๋ค. ๋ฐฐํฌ ํ์ดํ๋ผ์ธ(CI/CD)์ ๋ณ๋ ๋จ๊ณ ๋ก ๋นผ๋ ๊ฒ์ด ๊ฐ์ฅ ์์ ํฉ๋๋ค.
๐ ๋ ํผ๋ฐ์ค
๋ค์ ์ฅ: 05. CRUD ์กฐ์ (CRUD Operations)