테마
TurboRepo: Vercel의 고성능 빌드 시스템
TurboRepo는 Vercel이 개발한 고성능 모노레포 빌드 시스템으로, 스마트 캐싱, 태스크 파이프라인 기반 병렬 실행, Vercel 리모트 캐싱 등을 통해 빠르고 단순한 빌드 환경을 제공한다.
학습 목표
- TurboRepo의 핵심 철학(고성능, 단순함)을 이해한다
- TurboRepo의 주요 기능(스마트 캐싱, 병렬 실행, 리모트 캐싱)을 설명할 수 있다
- 태스크 파이프라인과 의존 관계 선언 방식을 이해한다
- turbo.json 설정의 주요 항목을 파악한다
- Vercel 플랫폼과의 통합 이점을 설명할 수 있다
1. TurboRepo 소개
TurboRepo는 스스로를 **"더 빌드 시스템(The Build System)"**이라고 부르며, 자바스크립트 및 타입스크립트 코드베이스를 위한 고성능 빌드 시스템을 표방한다.
TurboRepo의 핵심 특성:
| 특성 | 설명 |
|---|---|
| 운영 주체 | Vercel (Next.js를 만든 회사) |
| 설계 철학 | 최소한의 설정으로 최대한의 성능. 단순하지만 강력하게 |
| 적용 범위 | 모노레포 전용이 아님. 단일 프로젝트에서도 사용 가능 |
| 패키지 매니저 | npm, Yarn, pnpm 모두 지원 (pnpm 권장) |
| 구현 언어 | Rust로 작성되어 네이티브 수준의 성능 |
| 설정 파일 | turbo.json 하나로 핵심 설정 완료 |
TurboRepo는 원래 독립 프로젝트로 시작했으나, Vercel이 인수하면서 Vercel 생태계와 깊이 통합되었다. Next.js와 함께 사용할 때 특히 강력한 시너지를 발휘한다.
2. TurboRepo가 자랑하는 9가지 특성
TurboRepo 공식 사이트에서는 다음과 같은 특성을 강조한다. 이 중 빌드 성능에 직접적으로 영향을 미치는 핵심 항목을 살펴본다.
2.1 스마트 캐싱
TurboRepo의 캐싱은 기본값으로 활성화된다. turbo.json에 태스크를 등록하면 별도의 설정 없이 자동으로 캐싱이 동작한다. 이것은 NX나 Rush가 별도의 설정이나 조건(git 커밋 등)을 요구하는 것과 대조적이다.
2.2 콘텐츠 해시 기반 변경 감지
대부분의 빌드 도구는 파일의 타임스탬프를 기준으로 변경 여부를 판단한다. TurboRepo는 **파일의 실제 내용(content)**을 해시하여 판단한다. 파일을 열어 저장만 하고 내용을 바꾸지 않았다면, TurboRepo는 이를 "변경되지 않음"으로 올바르게 판단한다.
2.3 최대 병렬화
TurboRepo는 태스크 파이프라인에서 정의된 의존 관계를 분석하여, 의존 관계가 없는 태스크는 모든 CPU 코어를 활용해 동시에 실행한다.
3. 태스크 파이프라인과 의존 관계
TurboRepo의 가장 핵심적인 개념은 **태스크 파이프라인(task pipeline)**이다. turbo.json에서 태스크 간의 의존 관계를 선언적으로 정의하면, TurboRepo가 자동으로 실행 순서와 병렬화를 최적화한다.
3.1 의존 관계 선언
json
{
"tasks": {
"build": {
"dependsOn": ["^build"],
"outputs": ["dist/**", ".next/**"]
},
"test": {
"dependsOn": ["build"],
"outputs": []
},
"lint": {
"outputs": []
},
"dev": {
"cache": false,
"persistent": true
}
}
}dependsOn의 의미:
| 표현 | 의미 |
|---|---|
"^build" | **의존하는 패키지(upstream)**의 build가 먼저 완료되어야 한다 |
"build" | 같은 패키지 내의 build가 먼저 완료되어야 한다 |
[] (빈 배열) | 의존 관계 없음. 즉시 실행 가능 |
^ 접두사는 패키지 간 의존 관계를 나타내고, 접두사 없이 태스크 이름만 쓰면 같은 패키지 내의 태스크 의존 관계를 나타낸다.
3.2 실행 흐름 예시
모노레포에 shared, web, docs 세 패키지가 있고, web과 docs가 shared에 의존한다고 가정하자.
실행 흐름 해설:
- Phase 1:
lint는 의존 관계가 없으므로 세 패키지 모두 즉시 병렬 실행된다.shared의build도 upstream 의존이 없으므로 동시에 시작된다. - Phase 2:
shared의build가 완료되면,web과docs의build가 병렬로 시작된다.shared의test도 시작된다(test는 같은 패키지의build에 의존). - Phase 3: 각 패키지의
build가 완료되면 해당 패키지의test가 실행된다.
이 모든 순서 결정과 병렬화가 turbo.json의 선언적 설정만으로 자동 처리된다.
4. turbo.json 설정 상세
turbo.json은 TurboRepo의 유일한 핵심 설정 파일이다. 전체 모노레포의 태스크 파이프라인, 캐싱, 출력물 등을 정의한다.
json
{
"$schema": "https://turbo.build/schema.json",
"globalDependencies": [
"**/.env.*local"
],
"globalEnv": [
"NODE_ENV",
"CI"
],
"tasks": {
"build": {
"dependsOn": ["^build"],
"inputs": ["src/**", "tsconfig.json"],
"outputs": ["dist/**", ".next/**", "!.next/cache/**"],
"env": ["NEXT_PUBLIC_API_URL"]
},
"test": {
"dependsOn": ["build"],
"inputs": ["src/**", "test/**", "jest.config.*"],
"outputs": ["coverage/**"],
"env": ["CI"]
},
"lint": {
"inputs": ["src/**", ".eslintrc.*"],
"outputs": []
},
"dev": {
"cache": false,
"persistent": true
},
"clean": {
"cache": false
}
}
}설정 항목 해설:
| 항목 | 설명 |
|---|---|
globalDependencies | 모든 태스크의 캐시 키에 포함되는 파일 패턴. 환경 변수 파일 등 |
globalEnv | 모든 태스크의 캐시 키에 포함되는 환경 변수 |
tasks | 각 태스크의 의존 관계, 입력, 출력, 캐싱 설정 |
dependsOn | 이 태스크 실행 전에 완료되어야 하는 태스크 (^는 upstream) |
inputs | 캐시 키에 포함되는 입력 파일 패턴. 이 파일이 변경되면 캐시 무효화 |
outputs | 캐싱할 출력물의 경로. 캐시 히트 시 이 파일들이 복원됨 |
env | 이 태스크의 캐시 키에 포함되는 환경 변수 |
cache: false | 이 태스크의 결과를 캐싱하지 않음 (dev 서버 등) |
persistent: true | 장시간 실행되는 태스크 (dev 서버 등). 다른 태스크를 블로킹하지 않음 |
4.1 워크스페이스별 설정 오버라이드
루트의 turbo.json에서 정의한 설정을 특정 워크스페이스에서 오버라이드할 수 있다.
json
// apps/my-app/turbo.json
{
"extends": ["//"],
"tasks": {
"build": {
"outputs": [".next/**", "!.next/cache/**"]
}
}
}"extends": ["//"]는 루트 turbo.json을 상속한다는 의미다. 각 워크스페이스의 특수한 설정만 오버라이드하면 된다.
5. TurboRepo 명령어
bash
# 특정 태스크 실행 (전체 패키지)
turbo run build
turbo run test
turbo run lint test build # 여러 태스크 동시 실행
# 특정 패키지만 필터링
turbo run build --filter=my-app
turbo run test --filter=my-utils
# 의존 패키지까지 포함하여 필터링
turbo run build --filter=my-app...
# 변경된 패키지만 실행 (git 기반)
turbo run build --filter=[HEAD^1]
# 캐시 비우기
turbo run build --force
# 빌드 프로파일 생성 (Chrome DevTools에서 분석 가능)
turbo run build --profile
# 코드 생성 (빈 워크스페이스)
turbo gen workspace --name my-lib
# Vercel 리모트 캐싱 연결
turbo link--filter 옵션의 다양한 사용:
| 패턴 | 의미 |
|---|---|
--filter=my-app | my-app 패키지만 |
--filter=my-app... | my-app과 그 의존 패키지 전부 |
--filter=...my-app | my-app에 의존하는 패키지 전부 |
--filter=[HEAD^1] | 마지막 커밋 이후 변경된 패키지 |
--filter=./apps/* | apps 디렉토리 내의 모든 패키지 |
6. Vercel과의 통합
TurboRepo는 Vercel 생태계와 깊이 통합되어 있다.
6.1 리모트 캐싱
bash
# Vercel 계정에 연결
turbo link
# 이후 빌드 결과가 자동으로 Vercel에 캐싱
turbo run buildturbo link 한 번으로 리모트 캐싱이 활성화된다. NX Cloud에 비해 설정이 매우 단순하다.
리모트 캐싱이 활성화되면:
- 로컬에서 빌드한 결과가 Vercel 클라우드에 저장된다.
- CI에서 같은 코드를 빌드하면 클라우드 캐시를 다운로드하여 즉시 완료한다.
- 팀원 간에도 캐시가 공유되어 첫 빌드도 빠르게 완료된다.
6.2 Vercel 배포와의 시너지
Vercel에 모노레포를 배포할 때, TurboRepo의 --filter 기능으로 변경된 앱만 선택적으로 배포할 수 있다. 이는 배포 시간 단축과 불필요한 재배포 방지에 도움이 된다.
6.3 Next.js와의 궁합
TurboRepo는 Next.js 프로젝트를 1등 시민(first-class citizen)으로 지원한다. create-turbo 스캐폴딩 도구는 기본적으로 Next.js 앱과 공유 패키지를 포함한 모노레포 구조를 생성한다.
bash
# TurboRepo 모노레포 프로젝트 생성
npx create-turbo@latest my-turborepo7. TurboRepo를 선택해야 하는 경우
TurboRepo가 적합한 프로젝트:
- 단순한 설정으로 빠르게 시작하고 싶은 프로젝트
- Vercel/Next.js 생태계를 이미 사용하고 있거나 도입 예정인 프로젝트
- 캐싱과 병렬 실행에 집중하여 빌드 성능을 극대화하고 싶은 프로젝트
- 학습 곡선을 최소화하면서 모노레포의 이점을 누리고 싶은 프로젝트
- pnpm + TurboRepo 조합으로 가볍게 시작하고 싶은 프로젝트
TurboRepo보다 다른 도구가 나은 경우:
- npm 패키지 게시, 버전 관리 자동화가 필요하면 -> Lerna
- 프로젝트 그래프 시각화, 모듈 경계 강제, 플러그인 생태계가 필요하면 -> NX
- 대규모 팀의 정책 관리, 의존성 승인이 필요하면 -> Rush
8. 네 가지 도구 최종 비교
| 비교 항목 | Lerna | NX | Rush | TurboRepo |
|---|---|---|---|---|
| 한 줄 요약 | 오리지널 모노레포 관리 | 최다 기능 빌드 시스템 | 대규모 팀 모노레포 매니저 | 고성능 빌드 시스템 |
| 설정 복잡도 | 낮음 | 중간~높음 | 높음 | 낮음 |
| 캐싱 방식 | NX 기반 | 입력 해시 | git 커밋 기반 | 콘텐츠 해시 |
| 병렬화 | NX 기반 | 자동 | 자동 | 자동 (Rust 네이티브) |
| 버전 관리 | 내장 (강점) | 없음 | 내장 | 없음 |
| 프로젝트 그래프 | NX 기반 | 내장 (강점) | 없음 | 없음 |
| 정책 관리 | 없음 | 모듈 경계 | 내장 (강점) | 없음 |
| 리모트 캐싱 | NX Cloud | NX Cloud | Azure 등 | Vercel |
| 최적 사용 사례 | 오픈소스 라이브러리 게시 | 대규모 엔터프라이즈 | MS 환경/정책 중시 | 일반 프로젝트/빠른 시작 |
핵심 정리
| 핵심 개념 | 요약 |
|---|---|
| TurboRepo의 철학 | 최소한의 설정으로 최대한의 성능. turbo.json 하나로 핵심 설정 완료 |
| 스마트 캐싱 | 콘텐츠 해시 기반으로 파일 내용을 정확히 분석. 기본값으로 캐싱 활성화 |
| 태스크 파이프라인 | dependsOn으로 태스크 간 의존 관계를 선언하면 자동으로 순서 결정 및 병렬화 |
^ 접두사 | upstream 패키지(의존되는 패키지)의 태스크를 의미. "^build" = 의존 패키지의 build 선행 |
| 리모트 캐싱 | turbo link 한 번으로 Vercel 리모트 캐싱 활성화. 팀/CI 캐시 공유 |
--filter 옵션 | 특정 패키지, 의존 체인, 변경된 패키지 등을 유연하게 필터링 |
| Vercel 시너지 | Next.js + Vercel 배포와 결합할 때 최적의 개발 경험을 제공한다 |
다음 단계
이번 장까지 모노레포 빌드 시스템 도구(Lerna, NX, Rush, TurboRepo)의 개념과 핵심 기능을 학습했다. 다음 장에서는 빌드 시스템 도구 위에서 동작하는 트랜스파일러와 번들러에 대해 학습하고, 모노레포 환경에서의 코드 변환과 번들링 전략을 이해한다.