Ch6. Vercel 배포 전략
모노레포 배포 구조, Preview 환경, Rolling Releases, 환경 변수 관리, turbo prune
핵심 요약
- 모노레포는 앱 하나당 Vercel 프로젝트 하나를 만들고, 각 프로젝트는 동일 레포에 Root Directory와
turbo run build --filterBuild Command만 다르게 설정합니다. turbo-ignore(Ignored Build Step)로 변경 없는 앱의 빌드를 건너뛰고, Preview는 PR 생성·커밋·머지·닫기 이벤트에 자동 반응합니다.- Rolling Releases는 production을 10%→50%→100%로 단계별로 노출하고, Skew Protection이 클라이언트·backend 배포 버전 불일치를 막습니다.
- Deployment Protection(Authentication·Password·Trusted IPs·Bypass)으로 Preview·non-production URL 접근을 제한합니다.
- 오래 실행되는 Route Handler/Server Action은 Fluid Compute를 검토하되 timeout을 늘리기 전 idempotency·retry·correlation id·fallback을 먼저 설계하고, 자체 인프라 배포는
turbo prune --docker로 경량화합니다.
모노레포 배포 구조
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')}`
});Rolling Releases와 Skew Protection
Production 배포가 곧바로 100% 트래픽을 받는 구조는 엔터프라이즈 서비스에서 위험합니다. Vercel Rolling Releases를 쓰면 새 production deployment를 10% -> 50% -> 100%처럼 단계적으로 노출하고, 단계마다 오류율과 성능 지표를 비교한 다음 승격하거나 중단합니다.
# 10분 동안 10%, 20분 동안 50%, 이후 100%로 승격
vercel rolling-release configure --cfg '{"enabled":true,"advancementType":"automatic","stages":[{"targetPercentage":10,"duration":10},{"targetPercentage":50,"duration":20},{"targetPercentage":100}]}'
# 이후 production deploy가 rolling release 후보가 됨
vercel deploy --prod| 운영 항목 | 권장 기준 |
|---|---|
| 첫 단계 | 5~10% 트래픽으로 시작 |
| 관측 지표 | 오류율, latency, Core Web Vitals, 전환 이벤트 |
| 중단 기준 | P0/P1 오류, 핵심 API 오류율 상승, 결제/로그인 실패 |
| 복구 방식 | Rolling Release abort 또는 Instant Rollback |
Rolling Releases를 쓸 때는 Skew Protection을 함께 켭니다. 클라이언트가 특정 배포 버전을 받았다면 이후 API 요청도 같은 배포 버전의 backend 코드로 라우팅하므로, rollout 도중 클라이언트와 서버 버전이 어긋나는 문제를 줄입니다.
Deployment Protection
Preview URL은 PR 검증에 유용하지만, 고객 데이터와 staging API에 접근한다면 공개 URL로 두면 안 됩니다. Vercel Deployment Protection으로 Preview와 non-production 배포 접근을 제한하세요.
| 보호 방식 | 적용 시점 |
|---|---|
| Vercel Authentication | 사내 구성원만 Preview 접근 |
| Password Protection | 외부 파트너·고객 검토 링크 |
| Trusted IPs | 사내망·VPN에서만 접근 |
| Protection Bypass for Automation | Playwright, QA bot, webhook 검증 |
자동화 테스트가 Preview를 열어야 한다면 우회 토큰을 따로 발급하고, 테스트 로그에 토큰이 새지 않도록 GitHub Secrets/Vercel Environment Variables로만 주입합니다.
환경 변수 계층
| 스코프 | 적용 대상 | 용도 |
|---|---|---|
| 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 파라미터를 조정하세요.
Fluid Compute와 장기 실행 작업
Next.js 앱 안의 Route Handler나 Server Action이 AI 호출, 리포트 생성, 대용량 webhook 처리처럼 오래 걸리는 작업을 맡는다면 Vercel Fluid Compute를 검토합니다. Fluid Compute는 함수 실행 시간을 늘리고 동시 요청 처리를 개선하지만, 그렇다고 모든 문제를 함수 안에서 풀라는 말은 아닙니다.
| 작업 유형 | 권장 위치 |
|---|---|
| 짧은 SSR/API 요청 | 기본 Vercel Functions |
| AI 요약, 파일 변환, 긴 webhook | Fluid Compute |
| 재시도·지연·팬아웃이 필요한 작업 | Queue/Workflow 계층 |
| DB 스키마 마이그레이션 | CI/CD 또는 운영 runbook |
프로덕션에서는 함수 timeout을 늘리기 전에 idempotency key, retry 정책, 로그 correlation id, 사용자-facing fallback을 먼저 설계하세요.
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 플랫폼 변경
| 항목 | 설명 |
|---|---|
| Rolling Releases | production 배포를 단계적으로 노출하고 지표를 비교 |
| Skew Protection | rollout 중 클라이언트와 backend 배포 버전 불일치 방지 |
| Deployment Protection | Preview와 non-production URL 접근 제어 |
| Fluid Compute | 오래 실행되는 함수와 동시성 높은 API에 적합 |
| Firewall/DDoS Protection | WAF 규칙, 봇 탐지, IP 차단, DDoS 방어 |
| Turbopack 프로덕션 | Next.js 16 + Vercel에서 Turbopack 프로덕션 빌드 기본 |
Next.js 16에서 middleware.ts를 proxy.ts로 바꾼 변경은 Vercel 배포에도 그대로 반영됩니다. 마이그레이션할 때 파일명 변경을 확인하세요.
참고 문서
- Vercel: Monorepos (영어)
- Vercel: Environment Variables (영어)
- Vercel: Rolling Releases (영어)
- Vercel: Deployment Protection (영어)
- Vercel: Fluid Compute (영어)
- Turborepo: Pruning (영어)
- Turborepo: turbo-ignore (영어)
- Vercel: Firewall (영어)