stack-analysis
CHAPTER 41 / 90
읽기 약 2분
FUNCTION
마이그레이션: Prisma Migrate 실전
핵심 개념
schema.prisma·migrate dev/deploy·zero-downtime·롤백 — 안전한 DB 변경.
본문
Prisma 셋업
pnpm add prisma @prisma/client
pnpm dlx prisma init// schema.prisma
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
model User {
id String @id @default(cuid())
email String @unique
name String
posts Post[]
createdAt DateTime @default(now())
@@index([createdAt])
}
model Post {
id String @id @default(cuid())
title String
content String @db.Text
authorId String
author User @relation(fields: [authorId], references: [id])
published Boolean @default(false)
createdAt DateTime @default(now())
@@index([authorId, createdAt(sort: Desc)])
@@index([published])
}마이그레이션 명령
# 개발 — 스키마 변경 후
pnpm dlx prisma migrate dev --name add_user_email_unique
# → migrations/20260429_add_user_email_unique/migration.sql 생성
# → DB 적용 + Prisma Client 재생성
# 프로덕션
pnpm dlx prisma migrate deploy
# → 미적용 마이그레이션 실행 (생성 X)
# DB 재설정 (개발용)
pnpm dlx prisma migrate resetZero-Downtime 마이그레이션
❌ 위험한 변경:
1. 컬럼 이름 변경 (rename)
2. 컬럼 타입 변경 (string → number)
3. NOT NULL 추가 (기존 데이터에)
4. 큰 테이블에 인덱스 추가 (블로킹)
✅ 안전한 패턴 — Expand & Contract:
[Phase 1: Expand]
- 새 컬럼 추가 (nullable)
- 새 코드는 양쪽 쓰기 (dual-write)
- 백필 (background)
[Phase 2: Migrate]
- 새 컬럼이 채워질 때까지 대기
- 새 코드는 새 컬럼만 읽기
[Phase 3: Contract]
- 옛 컬럼 제거
- 코드 정리예시 — 컬럼 rename
// ❌ 한 번에
model User {
username String // name → username으로 변경
}
// ✅ 단계별
// Phase 1
model User {
name String
username String? // 추가
}
// 코드: 양쪽 쓰기
await prisma.user.update({ where, data: { name: x, username: x } });
// Phase 2 — 백필
await prisma.$executeRaw`UPDATE "User" SET username = name WHERE username IS NULL`;
// Phase 3
model User {
username String // name 제거 + NOT NULL
}큰 테이블 인덱스 — CONCURRENTLY
-- ❌ 블로킹
CREATE INDEX idx_posts_created ON posts(created_at);
-- ✅ 비차단 (PostgreSQL)
CREATE INDEX CONCURRENTLY idx_posts_created ON posts(created_at);
-- Prisma는 자동으로 CONCURRENTLY 안 함
-- → 수동 마이그레이션 SQL 작성
-- migration.sql
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_posts_created ON "Post"("createdAt");시드 데이터
// prisma/seed.ts
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();
async function main() {
await prisma.user.upsert({
where: { email: 'admin@example.com' },
create: { email: 'admin@example.com', name: 'Admin', role: 'ADMIN' },
update: {},
});
}
main().finally(() => prisma.$disconnect());
// package.json
{
"prisma": { "seed": "tsx prisma/seed.ts" }
}
// 실행
pnpm dlx prisma db seed마이그레이션 롤백
# Prisma는 자동 롤백 없음 → 수동 작성
# migrations/20260429_xxx/migration.sql
ALTER TABLE "Post" ADD COLUMN "summary" TEXT;
# rollback.sql (수동 작성·관리)
ALTER TABLE "Post" DROP COLUMN "summary";
# 프로덕션 롤백 절차:
1. 백업 확인 (RDS 자동 스냅샷)
2. 새 마이그레이션으로 역방향 변경
3. 또는 백업에서 PITR (Point-In-Time Recovery)환경 분리
# .env.development
DATABASE_URL="postgresql://localhost/myapp_dev"
# .env.staging
DATABASE_URL="postgresql://stage-db.../myapp_stage"
# .env.production (Vercel/Railway 환경변수)
DATABASE_URL="postgresql://prod-db.../myapp_prod"
# CI/CD 흐름:
1. PR 머지 → staging migrate deploy
2. 검증 통과 → production migrate deploy
3. 실패 시 alert + 롤백 절차다음 챕터
CH.42 "Redis 패턴: 캐시/세션/큐/Pub-Sub".
AI 프롬프트
🤖 AI에게 잘 물어보는 법 — 모델·전략별 프롬프트
Claude
무료: Sonnet 4.6 / Pro $20/mo: Opus 4.6
내 코드의 DB 마이그레이션 부분을 분석해서 실전 분석 + 개선 우선순위를 알려줘.
ChatGPT
무료: GPT-5.5 / Plus $20/mo: GPT-5.5 Pro
DB 마이그레이션 관련 인기 라이브러리/패턴 5개를 비교 분석해서 패턴 추출를 알려줘.
Gemini
무료: 2.5 Flash / Pro $19.99/mo: 3.1 Pro
내 프로젝트 전체에서 DB 마이그레이션 최적화 가능 위치를 보고해줘.
Grok
무료: Grok 4.1 / SuperGrok $30/mo
2026년 한국 백엔드 시장의 DB 마이그레이션 트렌드를 솔직히 알려줘.
⭐ 이것만 기억하세요
마이그레이션: Prisma Migrate 실전은 이 3가지만 확실히 잡으세요
1.migrate dev = 개발(생성+적용), migrate deploy = 프로덕션(적용만)
2.Zero-downtime은 Expand & Contract 패턴 — 점진적 전환
3.큰 테이블 인덱스는 CONCURRENTLY — 수동 SQL 필요
공유하기
진행도 41 / 90