Ch6. Vercel 배포 전략
모노레포 배포 구조, Preview 환경, 환경 변수 관리, turbo prune
모노레포 배포 구조
Turborepo 모노레포에서는 앱 하나당 Vercel 프로젝트 하나를 생성합니다.
각 프로젝트는 동일 레포를 바라보되, Root Directory와 Build Command가 다릅니다.
Root Directory와 Build Command
// Vercel 프로젝트 설정 (web)
{
"rootDirectory": "apps/web",
"buildCommand": "cd ../.. && turbo run build --filter=web",
"installCommand": "yarn install",
"outputDirectory": ".next"
}buildCommand에서 루트로 이동 후 turbo run build --filter를 실행하면, 의존 패키지(@org/ui, @org/utils)가 먼저 빌드된 후 앱이 빌드됩니다.
Ignored Build Step
Vercel의 Ignored Build Step 설정으로 변경 없는 앱의 빌드를 건너뛸 수 있습니다:
npx turbo-ignore이 명령은 현재 앱과 의존 패키지에 변경이 없으면 빌드를 스킵합니다.
Preview 환경 자동화
| 이벤트 | 동작 | URL 패턴 |
|---|---|---|
| PR 생성 | Preview 자동 배포 | web-{hash}.vercel.app |
| PR 커밋 추가 | Preview 업데이트 | 동일 URL |
| PR 머지 | Production 배포 | web.acme.com |
| PR 닫기 | Preview 자동 삭제 | - |
# .github/workflows/preview-comment.yml — PR에 Preview URL 코멘트
- name: Comment Preview URLs
uses: actions/github-script@v7
with:
script: |
const urls = [
`web: https://web-${context.sha.slice(0,8)}.vercel.app`,
`admin: https://admin-${context.sha.slice(0,8)}.vercel.app`,
];
github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: `## Preview URLs\n${urls.join('\n')}`
});환경 변수 계층
| 스코프 | 적용 대상 | 용도 |
|---|---|---|
| Production | 프로덕션 배포만 | DB URL, API 키 |
| Preview | PR Preview만 | 스테이징 DB, 테스트 API 키 |
| Development | vercel dev 로컬 | 로컬 DB |
| 프로젝트 공통 | 모든 환경 | NEXT_PUBLIC_* 앱 설정 |
# Vercel CLI로 환경 변수 관리
vercel env add DATABASE_URL production
vercel env add DATABASE_URL preview
vercel env pull .env.local # 로컬에 환경 변수 동기화프로덕션 시크릿은 절대 .env 파일에 저장하지 않습니다. Vercel 대시보드 또는 CLI로만 관리하세요.
Prisma 마이그레이션과 배포
모노레포에서 Prisma 마이그레이션은 @org/db 패키지에서 관리합니다:
# 로컬 개발 — 마이그레이션 생성
yarn workspace @acme/db db:migrate
# CI/CD — 마이그레이션 적용 (빌드 전)
yarn workspace @acme/db prisma migrate deploy
# Vercel 빌드 시 — Prisma Client 생성
# turbo.json에서 build 전에 db:generate를 실행하도록 설정// turbo.json — Prisma generate를 빌드 의존성으로 설정
{
"tasks": {
"db:generate": {
"cache": false
},
"build": {
"dependsOn": ["^build", "^db:generate"],
"inputs": ["$TURBO_DEFAULT$", ".env*"],
"outputs": [".next/**", "!.next/cache/**"]
}
}
}Vercel에서 Prisma 주의사항
Vercel은 서버리스 환경이므로 DB 커넥션 풀 관리가 중요합니다.
Neon, Supabase, PlanetScale 같은 서버리스 호환 DB를 사용하거나, Prisma의 connection_limit 파라미터를 조정하세요.
Pruned Subsets (turbo prune)
turbo prune는 특정 앱과 그 의존성만 추출하여 경량 모노레포를 생성합니다. 자체 인프라(Docker) 배포 시 빌드 컨텍스트를 최소화할 때 유용합니다.
# apps/web과 의존 패키지만 추출
turbo prune web --docker
# 생성되는 구조:
# out/
# ├── json/ # package.json만 (설치용)
# │ ├── apps/web/package.json
# │ ├── packages/db/package.json
# │ └── packages/ui/package.json
# ├── full/ # 전체 소스
# │ ├── apps/web/
# │ ├── packages/db/
# │ └── packages/ui/
# └── package.json # 루트 (lockfile 포함)# Dockerfile (Next.js standalone 빌드)
FROM node:22-alpine AS pruned
WORKDIR /app
COPY . .
RUN npx turbo prune web --docker
FROM node:22-alpine AS installer
WORKDIR /app
COPY --from=pruned /app/out/json/ .
RUN yarn install --frozen-lockfile
FROM node:22-alpine AS builder
WORKDIR /app
COPY --from=installer /app/ .
COPY --from=pruned /app/out/full/ .
RUN yarn workspace @acme/db prisma generate
RUN yarn turbo run build --filter=web
FROM node:22-alpine AS runner
WORKDIR /app
COPY --from=builder /app/apps/web/.next/standalone ./
COPY --from=builder /app/apps/web/.next/static ./.next/static
COPY --from=builder /app/apps/web/public ./public
CMD ["node", "server.js"]2025~2026 Vercel 플랫폼 변경
| 항목 | 설명 |
|---|---|
| Firewall GA | 배포별 WAF 규칙 설정, 봇 탐지, IP 차단 |
| DDoS Protection | 엔터프라이즈 플랜 자동 DDoS 방어 |
| Conformance | ESLint/TypeScript 규칙을 Vercel 대시보드에서 중앙 관리 |
| Vercel AI SDK 5.x | 스트리밍 AI 응답, 도구 호출, 멀티 프로바이더 지원 |
| Turbopack 프로덕션 | Next.js 16 + Vercel에서 Turbopack 프로덕션 빌드 기본 |
Next.js 16의 proxy.ts(기존 middleware.ts) 리네임이 Vercel 배포에도 반영됩니다. 마이그레이션 시 파일명 변경을 확인하세요.
참고 문서
- Vercel: Monorepos (영어)
- Vercel: Environment Variables (영어)
- Turborepo: Pruning (영어)
- Turborepo: turbo-ignore (영어)
- Vercel: Firewall (영어)