๐Ÿ’ก ๊ธฐ๋ณธ ์ƒ์„ฑ

2026๋…„ 4์›” 30์ผ ์ˆ˜์ •๋จ

๐Ÿ“‹ ๊ฐœ์š”

DB ์Šคํ‚ค๋งˆ๋ฅผ ์•ˆ์ „ํ•˜๊ฒŒ ๋ณ€๊ฒฝํ•˜๊ณ  ์ „ํŒŒํ•˜๋Š” ์›Œํฌํ”Œ๋กœ์šฐ์ž…๋‹ˆ๋‹ค. ํŒ€ ๋‹จ์œ„ ํ˜‘์—…๊ณผ ๋ฐฐํฌ ์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ๋‹ค๋ฃน๋‹ˆ๋‹ค.

๐Ÿ“‹ ๋ชฉ์ฐจ

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 migrate

custom (์ˆ˜๋™ 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 ๋Œ€์‹œ๋ณด๋“œ์—์„œ ์ง์ ‘ ์ปฌ๋Ÿผ ์ถ”๊ฐ€ํ•จ)

  1. ์ง„๋‹จ:
    npx drizzle-kit check
    # -> ์ฐจ์ด์ ์„ ๋ฆฌํฌํŠธ๋กœ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค.
  2. ํ•ด๊ฒฐ A (์ฝ”๋“œ ๊ธฐ์ค€ ๋™๊ธฐํ™”):
    ๋‹ค์‹œ push ํ•˜๊ฑฐ๋‚˜ generateํ•ด์„œ DB๋ฅผ ๋‚ด ์ฝ”๋“œ์— ๋งž์ถฅ๋‹ˆ๋‹ค. (DB ๋ณ€๊ฒฝ์‚ฌํ•ญ ๋ฎ์–ด์”€)
  3. ํ•ด๊ฒฐ B (DB ๊ธฐ์ค€ ๋™๊ธฐํ™”):
    introspect (๋˜๋Š” pull) ๋ช…๋ น์–ด๋กœ DB ์ƒํƒœ๋ฅผ ์Šคํ‚ค๋งˆ ํŒŒ์ผ๋กœ ์—ญ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.
    npx drizzle-kit pull

์ƒํ™ฉ 2: ์ถฉ๋Œ (Conflicts) โš”๏ธ

๋™๋ฃŒ A์™€ B๊ฐ€ ๋™์‹œ์— ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ํŒŒ์ผ์„ ๋งŒ๋“ค์–ด์„œ ์ปค๋ฐ‹ํ–ˆ์Šต๋‹ˆ๋‹ค.

  • 0005_add_post.sql (A)
  • 0005_add_comment.sql (B)
    ์ˆœ์„œ ๋ฒˆํ˜ธ๊ฐ€ ๊ฒน์ณค๋„ค์š”!

ํ•ด๊ฒฐ:

  1. ํŒŒ์ผ ์ด๋ฆ„์˜ ์ˆซ์ž๋ฅผ ์ˆ˜์ •ํ•˜๊ฑฐ๋‚˜ (์ˆ˜๋™)
  2. ๊ฐ€์žฅ ์ตœ์‹  ์Šค๋ƒ…์ƒท์„ ์‚ญ์ œํ•˜๊ณ  ๋‹ค์‹œ generate ํ•ฉ๋‹ˆ๋‹ค.
  3. Drizzle Kit์ด ์•Œ์•„์„œ ์ˆœ์„œ๋ฅผ ์žฌ์กฐ์ •ํ•˜๊ธฐ๋„ ํ•ฉ๋‹ˆ๋‹ค. (๋ฒ„์ „์—…๋˜๋ฉด์„œ ๋˜‘๋˜‘ํ•ด์ง)

๐Ÿš€ 4. ๋ฐฐํฌ ์ „๋žต (Production Deployment)

์•ˆ์ „ํ•œ ๋ฐฐํฌ ์น˜ํŠธ์‹œํŠธ CheckList โœ…

  1. Schema Sync: ๋กœ์ปฌ์—์„œ drizzle-kit generate ์™„๋ฃŒ ํ›„ ์ปค๋ฐ‹.
  2. Dry Run: ์‹ค์ œ ๋ฐฐํฌ ์ „ ํ…Œ์ŠคํŠธ DB์— ๋จผ์ € ์ ์šฉํ•ด๋ด„.
  3. Backup: (์šด์˜ ํ™˜๊ฒฝ) ๋ฐฐํฌ ์ง์ „ ์Šค๋ƒ…์ƒท/๋ฐฑ์—… ํ•„์ˆ˜.
  4. 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)์˜ ๋ณ„๋„ ๋‹จ๊ณ„ ๋กœ ๋นผ๋Š” ๊ฒƒ์ด ๊ฐ€์žฅ ์•ˆ์ „ํ•ฉ๋‹ˆ๋‹ค.


๐Ÿ“ ๋งˆ๋ฌด๋ฆฌ ํ€ด์ฆˆ

Q1. drizzle-kit generate์™€ drizzle-kit migrate์˜ ์ฐจ์ด๋Š” ๋ฌด์—‡์ธ๊ฐ€์š”?

โœ… ์ •๋‹ต: generate๋Š” ์Šคํ‚ค๋งˆ ๋ณ€๊ฒฝ์„ SQL ํŒŒ์ผ๋กœ ๋งŒ๋“ค๊ณ , migrate๋Š” ๊ทธ SQL์„ ์‹ค์ œ DB์— ์ ์šฉํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ’ก ์ƒ์„ธ ํ•ด์„ค: generate๋Š” ์ปค๋ฐ‹ ๊ฐ€๋Šฅํ•œ ๋ณ€๊ฒฝ ๊ธฐ๋ก์„ ๋งŒ๋“œ๋Š” ๋‹จ๊ณ„์ž…๋‹ˆ๋‹ค. migrate๋Š” ์šด์˜ DB์— ์˜ํ–ฅ์„ ์ฃผ๋Š” ์‹คํ–‰ ๋‹จ๊ณ„๋ผ์„œ ๋ฐฐํฌ ํŒŒ์ดํ”„๋ผ์ธ์—์„œ ๋” ์กฐ์‹ฌํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

Q2. ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ drift๊ฐ€ ์œ„ํ—˜ํ•œ ์ด์œ ๋Š” ๋ฌด์—‡์ธ๊ฐ€์š”?

โœ… ์ •๋‹ต: ์ฝ”๋“œ์˜ ์Šคํ‚ค๋งˆ, ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ํŒŒ์ผ, ์‹ค์ œ DB ์ƒํƒœ๊ฐ€ ์„œ๋กœ ๋‹ฌ๋ผ์ ธ ๋‹ค์Œ ๋ณ€๊ฒฝ์ด ์˜ˆ์ธก ๋ถˆ๊ฐ€๋Šฅํ•ด์ง€๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

๐Ÿ’ก ์ƒ์„ธ ํ•ด์„ค: ์šด์˜ DB์— ์ง์ ‘ ์ปฌ๋Ÿผ์„ ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ํŒŒ์ผ์„ ๋ˆ„๋ฝํ•˜๋ฉด ํŒ€์›์˜ ๋กœ์ปฌ๊ณผ CI๊ฐ€ ๋‹ค๋ฅธ DB ๊ตฌ์กฐ๋ฅผ ๋ณด๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

Q3. ์˜์ฒ ์ด์˜ ํ…Œ์ŠคํŠธ ํƒ€์ž„: ์˜์ˆ˜๋„ค ์„œ๋น„์Šค๊ฐ€ K8s ํŒŒ๋“œ 3๊ฐœ๋กœ ๋ฐฐํฌ๋ฉ๋‹ˆ๋‹ค. ์•ฑ ์‹œ์ž‘ ์‹œ ๊ฐ ํŒŒ๋“œ๊ฐ€ migrate()๋ฅผ ์‹คํ–‰ํ•˜๋ฉด ์–ด๋–ค ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธธ ์ˆ˜ ์žˆ๋‚˜์š”?

โœ… ์ •๋‹ต: ์—ฌ๋Ÿฌ ์ธ์Šคํ„ด์Šค๊ฐ€ ๊ฐ™์€ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜์„ ๋™์‹œ์— ์ ์šฉํ•ด ๋ฝ, ์ถฉ๋Œ, ์ค‘๋ณต ์‹คํ–‰ ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๐Ÿ’ก ์ƒ์„ธ ํ•ด์„ค: ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜์€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์„œ๋ฒ„์˜ ์ผ๋ฐ˜ ์‹œ์ž‘ ๋กœ์ง๊ณผ ๋ถ„๋ฆฌํ•˜๋Š” ํŽธ์ด ์•ˆ์ „ํ•ฉ๋‹ˆ๋‹ค. CI/CD์˜ ๋ณ„๋„ ๋‹จ๊ณ„์—์„œ ํ•œ ๋ฒˆ๋งŒ ์‹คํ–‰ํ•˜๊ณ , ์‹คํŒจํ•˜๋ฉด ๋ฐฐํฌ๋ฅผ ๋ฉˆ์ถ”๋Š” ๊ตฌ์กฐ๊ฐ€ ์šด์˜์— ๋งž์Šต๋‹ˆ๋‹ค.

๐Ÿฃ ์˜์ฒ ์ด์˜ ํ‡ด๊ทผ ์ผ๊ธฐ

์˜ค๋Š˜์€ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜์„ DB ๋ณ€๊ฒฝ ๋ฒ„ํŠผ์ด ์•„๋‹ˆ๋ผ ๋ฐฐํฌ ๊ณ„์•ฝ์œผ๋กœ ๋ด์•ผ ํ•œ๋‹ค๋Š” ๊ฑธ ๋ฐฐ์› ๋‹ค. generate์™€ migrate๊ฐ€ ๋ถ„๋ฆฌ๋œ ์ด์œ ๋„ ์ด์ œ ์ดํ•ด๋œ๋‹ค.

์˜์ˆ˜ ๋‹˜์ด "๊ฒŒ์‹œํŒ ์ ๊ฒ€ ์—†์ด ์ปฌ๋Ÿผ ํ•˜๋‚˜ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์ฃ ?"๋ผ๊ณ  ๋ฌผ์—ˆ์„ ๋•Œ ์˜ˆ์ „ ๊ฐ™์œผ๋ฉด ๋ฐ”๋กœ ๊ฐ€๋Šฅํ•˜๋‹ค๊ณ  ํ–ˆ์„ ๊ฒƒ ๊ฐ™๋‹ค. ์ด์ œ๋Š” ๋ฐฑ์—…, ์ ์šฉ ์ˆœ์„œ, ์•ฑ ๋ฒ„์ „ ํ˜ธํ™˜์„ฑ, ํŒŒ๋“œ ๋™์‹œ ์‹คํ–‰๊นŒ์ง€ ๋จผ์ € ํ™•์ธํ•ด์•ผ ํ•œ๋‹ค.

๐Ÿ’ก "๋งˆ์ด๊ทธ๋ ˆ์ด์…˜์€ ์Šคํ‚ค๋งˆ ๋ณ€๊ฒฝ ํŒŒ์ผ์ด ์•„๋‹ˆ๋ผ ์šด์˜ DB์— ๋Œ€ํ•œ ์•ฝ์†์ด๋‹ค."

๋‚ด์ผ ๋ฐฐํฌ PR์„ ๋ณด๋ฉด SQL ๋‚ด์šฉ๋งŒ ๋ณด์ง€ ๋ง๊ณ , ๋กค๋ฐฑ ๊ฐ€๋Šฅ์„ฑ, drift ์—ฌ๋ถ€, CI์—์„œ ํ•œ ๋ฒˆ๋งŒ ์‹คํ–‰๋˜๋Š”์ง€๊นŒ์ง€ ์ฒดํฌํ•ด์•ผ๊ฒ ๋‹ค.

๐Ÿ”— ๋ ˆํผ๋Ÿฐ์Šค

๋‹ค์Œ ์žฅ: 05. CRUD ์กฐ์ž‘ (CRUD Operations)