| name | monorepo-turborepo |
| description | 모노레포 vs 멀티레포 선택 기준, Turborepo 구조 및 파이프라인 설정 |
모노레포 & Turborepo 패턴
소스: https://turbo.build/repo/docs | https://github.com/vercel/turborepo
검증일: 2026-06-20
모노레포 vs 멀티레포 선택 기준
| 기준 | 모노레포 | 멀티레포 |
|---|
| 패키지 간 의존성 | 많음 (공유 컴포넌트/유틸) | 적음 (독립 서비스) |
| 팀 규모 | 한 팀이 여러 패키지 관리 | 팀별 독립 저장소 |
| 배포 단위 | 함께 배포되는 경우 많음 | 완전 독립 배포 |
| 변경 영향도 | 한 곳에서 파악 가능 | 저장소마다 확인 필요 |
| 도구 통일 | 중앙 관리 | 팀마다 다를 수 있음 |
모노레포 적합:
- 디자인 시스템 + 여러 앱
- 풀스택 (프론트 + 백 + 공유 타입)
- 내부 패키지 라이브러리 운영 시
멀티레포 적합:
- 완전 독립 서비스 (마이크로서비스)
- 팀 / 기술 스택이 완전히 다른 경우
표준 폴더 구조
monorepo/
├── apps/ # 실행 애플리케이션
│ ├── web/ # Next.js 앱
│ ├── mobile/ # React Native
│ └── storybook/ # 컴포넌트 문서
├── packages/ # 공유 라이브러리
│ ├── ui/ # UI 컴포넌트 (tsup 빌드)
│ ├── utils/ # 유틸리티 함수
│ ├── types/ # 공유 TypeScript 타입
│ ├── tsconfig/ # 공유 tsconfig
│ └── eslint-config/ # 공유 ESLint 설정
├── turbo.json
├── pnpm-workspace.yaml # 또는 package.json workspaces
└── package.json # private: true
루트 package.json
{
"name": "myorg",
"private": true,
"packageManager": "pnpm@11.8.0",
"scripts": {
"build": "turbo run build",
"dev": "turbo run dev --parallel",
"lint": "turbo run lint",
"test": "turbo run test",
"typecheck": "turbo run typecheck"
}
}
pnpm-workspace.yaml
packages:
- "apps/*"
- "packages/*"
turbo.json 파이프라인
{
"$schema": "https://turbo.build/schema.json",
"globalEnv": ["NODE_ENV", "TURBO_TELEMETRY_DISABLED"],
"tasks": {
"build": {
"dependsOn": ["^build"],
"outputs": [".next/**", "dist/**", "!.next/cache/**"],
"cache": true
},
"dev": {
"cache": false,
"persistent": true
},
"lint": {
"cache": true,
"outputs": [".eslintcache"]
},
"test": {
"dependsOn": ["build"],
"outputs": ["coverage/**"],
"cache": true
},
"typecheck": {
"dependsOn": ["^typecheck"],
"cache": true
}
}
}
^ (caret) 의미: 의존하는 패키지의 해당 task를 먼저 실행
apps/web (ui 패키지 의존)
→ turbo run build 실행 시:
1. packages/ui build 먼저 실행
2. apps/web build 실행
워크스페이스 패키지 참조
{
"dependencies": {
"@myorg/ui": "workspace:*",
"@myorg/utils": "workspace:*",
"@myorg/types": "workspace:*"
}
}
workspace:* 장점:
- npm 레지스트리 조회 없이 로컬 패키지 직접 참조
- 발행(publish) 시 자동으로 실제 버전으로 변환
- 변경사항 즉시 반영 (빌드 필요 여부는 패키지 설정에 따라 다름)
내부 패키지 유형
UI 패키지 (컴포넌트 라이브러리)
{
"name": "@myorg/ui",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.mjs",
"require": "./dist/index.js"
}
},
"scripts": {
"build": "tsup src/index.ts --format esm,cjs --dts",
"dev": "tsup src/index.ts --format esm,cjs --dts --watch"
}
}
Config 패키지 (설정 공유)
{
"name": "@myorg/tsconfig",
"files": ["base.json", "nextjs.json", "react.json"]
}
{
"compilerOptions": {
"strict": true,
"target": "ES2020",
"moduleResolution": "bundler"
}
}
타입 전용 패키지
{
"name": "@myorg/types",
"main": "./src/index.ts",
"types": "./src/index.ts"
}
캐싱 전략
로컬 캐시 (기본)
turbo run build
turbo run build --force
turbo run build --dry
Remote Cache (Vercel)
turbo login
turbo link
장점: 팀원 간 / CI 간 캐시 공유 → 빌드 시간 40-85% 단축
환경변수와 캐시
{
"tasks": {
"build": {
"env": ["NEXT_PUBLIC_API_URL", "API_*"]
}
}
}
Changesets 버전 관리
pnpm add -D @changesets/cli
pnpm changeset init
pnpm changeset
pnpm changeset version
pnpm changeset publish
워크플로우:
개발 → changeset 작성 → PR 머지 → Release PR 자동 생성 → 승인 → 발행
자주 쓰는 Turbo 명령어
turbo run build --filter=@myorg/web
turbo run build --filter=@myorg/web...
turbo run build --filter=[main...HEAD]
turbo run build --affected
turbo run build --graph
turbo run dev --parallel
환경변수 관리
apps/web/
├── .env.local # 로컬 전용 (gitignore)
├── .env.development # 개발 환경
├── .env.production # 프로덕션 환경
└── .env.example # 필요 변수 목록 (git 포함)
❌ 루트에 .env 두지 않기: 각 앱이 독립적인 환경변수 관리 필요
✅ .env.example는 git에 포함: 팀원이 필요한 변수 파악 가능
흔한 실수
npm install react
pnpm add react --filter @myorg/web
pnpm add -D typescript --filter @myorg/ui
{
"tasks": {
"build": {
"env": ["NEXT_PUBLIC_API_URL"]
}
}
}
pnpm 11 + Turborepo 호환성 주의 (2026-06-20 기준)
주의: pnpm 11(2026-04-28 출시)은 Node.js 22+ 필수. pnpm 10에서 11로 업그레이드 시 CI/개발 환경도 Node.js 22 이상으로 함께 올려야 한다.
Turborepo + pnpm 11 알려진 이슈 (Turborepo 2.9.x):
| 이슈 | 원인 | 상태 |
|---|
| multi-document YAML lockfile 파싱 실패 | pnpm 11의 configDependencies 사용 시 멀티 YAML 문서 생성 | Turborepo가 단일 YAML 문서만 지원 |
patchedDependencies flat-string 형식 | pnpm 11이 {path, hash} 대신 flat 해시로 변경 | serde_yaml 타입 불일치 |
대응 방법:
configDependencies 또는 patchedDependencies 사용 중이면 Turborepo 최신 패치 확인 후 업그레이드
- 해당 기능 미사용 시 pnpm 11 + Turborepo 2.9.x 조합 일반적으로 동작