5 Optimization Techniques to Make Turborepo Builds 10x
이 글의 핵심
5 practical optimization techniques to dramatically reduce Turborepo build time, with benchmarks.
🎯 What You’ll Learn (Reading Time: 10 minutes)
TL;DR: Learn 5 optimization techniques to reduce Turborepo build time from 10 minutes to 1 minute. Includes practical benchmarks from caching strategies to Remote Cache. What You’ll Learn:
- ✅ Master Turborepo caching strategies
- ✅ Reduce team build time by 90% with Remote Cache
- ✅ Master parallel execution optimization techniques
- ✅ Improve build speed through dependency optimization Real-World Applications:
- 🔥 Reduce CI/CD build time by 10x
- 🔥 Maximize team development productivity
- 🔥 Cut build server costs by 90%
- 🔥 Minimize developer wait time Difficulty: Intermediate | Performance Gain: 10x | Benchmarks: Included
Problem: “Why is Turborepo so slow?”
If your builds are slow despite using Turborepo, you likely haven’t optimized it properly. Real Case Study:
Before optimization: 10-minute full build
After optimization: 1-minute full build
━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Improvement: 10x faster ⚡
This guide covers 5 battle-tested optimization techniques.
Optimization 1: Perfect Cache Configuration
Problem: Missing outputs Configuration
The most common mistake. Without proper outputs configuration, caching won’t work.
// ❌ Wrong configuration
{
"pipeline": {
"build": {
"outputs": [] // No caching!
}
}
}
// ✅ Correct configuration
{
"pipeline": {
"build": {
"outputs": [
".next/**",
"!.next/cache/**",
"dist/**",
"build/**"
]
}
}
}
Checklist:
{
"pipeline": {
"build": {
"outputs": [
".next/**", // Next.js
"dist/**", // General builds
"build/**", // CRA, Vite
".nuxt/**", // Nuxt
"out/**", // Next.js export
"public/build/**" // Remix
]
},
"test": {
"outputs": [
"coverage/**" // Test coverage
]
}
}
}
Impact:
No cache: 10 minutes every time
With cache: 10 minutes first build, 10 seconds after
━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Improvement: 60x faster 🚀
Optimization 2: Dependency Graph Optimization
Problem: Unnecessary Dependencies
// ❌ Everything depends on everything
{
"pipeline": {
"build": {
"dependsOn": ["^build", "lint", "test"] // Too many!
}
}
}
// ✅ Only necessary dependencies
{
"pipeline": {
"build": {
"dependsOn": ["^build"] // Only upstream builds
},
"deploy": {
"dependsOn": ["build", "test"] // Test only on deploy
}
}
}
Dependency Minimization Strategy:
{
"pipeline": {
// Build: only upstream dependencies
"build": {
"dependsOn": ["^build"]
},
// Lint: independent execution
"lint": {
"dependsOn": []
},
// Test: run after build
"test": {
"dependsOn": ["build"]
},
// Type check: only upstream builds
"type-check": {
"dependsOn": ["^build"]
}
}
}
Impact:
Excessive dependencies: sequential execution (slow)
Minimal dependencies: parallel execution (fast)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Improvement: 3-5x faster
Optimization 3: Leverage Remote Cache
Vercel Remote Cache (Free)
# 1. Connect Vercel account
npx turbo login
# 2. Link project
npx turbo link
# 3. Build (automatically uses Remote Cache)
turbo build
Impact:
Scenario: Developer A builds → Developer B builds
Without Remote Cache:
- A: 10 minutes
- B: 10 minutes
- Total: 20 minutes
With Remote Cache:
- A: 10 minutes (create cache)
- B: 10 seconds (download cache)
- Total: 10 minutes 10 seconds
━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Team-wide time savings: 50%
Self-Hosted Remote Cache Server
# Simple setup with Docker
docker run -d -p 8080:8080 \
-v turborepo-cache:/cache \
ghcr.io/fox1t/turborepo-remote-cache
# Configure in turbo.json
{
"remoteCache": {
"url": "http://localhost:8080"
}
}
Optimization 4: Maximize Parallel Execution
Problem: Sequential Execution
// ❌ Sequential execution (slow)
{
"pipeline": {
"build": {
"dependsOn": ["lint", "test", "type-check"]
}
}
}
lint (2min) → test (3min) → type-check (1min) → build (4min)
Total: 10 minutes
Solution: Parallel Execution
// ✅ Parallel execution (fast)
{
"pipeline": {
"build": {
"dependsOn": ["^build"]
},
"lint": {},
"test": {},
"type-check": {}
}
}
lint (2min) ┐
test (3min) ├─ parallel execution → build (4min)
type-check (1min) ┘
Total: 7 minutes (3 minutes saved)
Parallel Execution Commands:
# Run multiple tasks simultaneously
turbo run lint test type-check --parallel
# Build all packages simultaneously
turbo run build --parallel
# Limit concurrency (prevent CPU overload)
turbo run build --concurrency=4
Optimization 5: Selective Builds (Filtering)
Build Only Changed Packages
# Build only changed packages
turbo run build --filter=...[HEAD^1]
# Build specific package with dependencies
turbo run build --filter=web...
# Build specific package only (exclude dependencies)
turbo run build --filter=web
# Select multiple packages
turbo run build --filter=web --filter=docs
# Only when specific path changes
turbo run build --filter=./apps/*
Practical Examples:
# PR builds: only changed
turbo run build test --filter=...[origin/main]
# Specific app deployment: only that app
turbo run build --filter=web...
# Package change: only affected apps
turbo run build --filter=...@ui
Impact:
Full build: 10 minutes
Filtered build: 2 minutes
━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Improvement: 5x faster
Comprehensive Optimization Strategy
Before: Pre-Optimization
// turbo.json (before optimization)
{
"pipeline": {
"build": {
"outputs": [], // ❌ No caching
"dependsOn": ["lint", "test"] // ❌ Sequential execution
}
}
}
# Build command
turbo run build
# Result:
# lint: 2 minutes
# test: 3 minutes
# build: 5 minutes
# Total: 10 minutes (no cache)
After: Post-Optimization
// turbo.json (after optimization)
{
"pipeline": {
"build": {
"outputs": [".next/**", "dist/**"], // ✅ Cache enabled
"dependsOn": ["^build"] // ✅ Minimal dependencies
},
"lint": {}, // ✅ Parallel execution
"test": {} // ✅ Parallel execution
}
}
# Build command
turbo run build lint test --parallel
# Result:
# lint, test, build run in parallel: 5 minutes
# Cache hit: 10 seconds
# Total: 5 minutes first build, 10 seconds after
Improvement:
Before optimization: 10 minutes
After optimization: 10 seconds (cache hit)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Improvement: 60x faster ⚡⚡⚡
Real-World Benchmarks
Based on actual project (10 packages, Next.js + React):
| Optimization Stage | Build Time | Improvement |
|---|---|---|
| Default config | 10 minutes | - |
| + outputs config | 10min → 2min (cache hit) | 5x |
| + dependency optimization | 10min → 6min | 1.7x |
| + parallel execution | 6min → 4min | 1.5x |
| + Remote Cache | 4min → 30sec (team cache) | 8x |
| + filtering | 4min → 1min (changed only) | 4x |
| Total | 10min → 30sec | 20x |
Checklist
If your builds are slow, check these: Caching:
- Set build output paths in
outputs? - Is
.turbofolder in.gitignore? - Connected Remote Cache? (team projects) Dependencies:
- Any unnecessary tasks in
dependsOn? - No circular dependencies?
- Simplified to depend only on
^build? Parallelization: - Running independent tasks in parallel?
- Using
--parallelflag? - Is
--concurrencysetting appropriate? Filtering: - Building only changed parts in CI?
- Filtering when deploying specific apps?
Ready-to-Use Configuration
Optimized turbo.json
{
"$schema": "https://turbo.build/schema.json",
"globalDependencies": ["**/.env.*local"],
"pipeline": {
"build": {
"dependsOn": ["^build"],
"outputs": [
".next/**",
"!.next/cache/**",
"dist/**",
"build/**"
],
"env": [
"NEXT_PUBLIC_*",
"VITE_*"
]
},
"dev": {
"cache": false,
"persistent": true
},
"lint": {
"outputs": []
},
"test": {
"outputs": ["coverage/**"],
"dependsOn": []
},
"type-check": {
"dependsOn": ["^build"],
"outputs": []
}
}
}
package.json Scripts
{
"scripts": {
"build": "turbo run build",
"build:changed": "turbo run build --filter=...[HEAD^1]",
"dev": "turbo run dev --parallel",
"lint": "turbo run lint --parallel",
"test": "turbo run test --parallel",
"clean": "turbo run clean && rm -rf node_modules",
"clean:cache": "rm -rf .turbo"
}
}
CI/CD Optimization (GitHub Actions)
name: CI
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
# pnpm cache
- uses: pnpm/action-setup@v2
with:
version: 8
- uses: actions/setup-node@v3
with:
node-version: 18
cache: 'pnpm'
- run: pnpm install --frozen-lockfile
# Turborepo Remote Cache
- name: Build
run: pnpm turbo run build --filter=...[HEAD^1]
env:
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
TURBO_TEAM: ${{ secrets.TURBO_TEAM }}
# Test only changed
- name: Test
run: pnpm turbo run test --filter=...[HEAD^1]
CI Build Time:
Before optimization: 15 minutes
After optimization: 2-3 minutes (cache + filtering)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Improvement: 5-7x faster
Advanced Optimization
1. Leverage Incremental Builds
{
"pipeline": {
"build": {
"dependsOn": ["^build"],
"outputs": [".next/**"],
"cache": true,
"inputs": [
"src/**",
"public/**",
"package.json",
"next.config.js",
"tsconfig.json"
]
}
}
}
Specifying inputs triggers rebuild only when those files change.
2. Environment Variable Cache Keys
{
"pipeline": {
"build": {
"env": [
"NEXT_PUBLIC_API_URL",
"NEXT_PUBLIC_ENV"
]
}
}
}
Cache is invalidated when environment variables change.
3. Selective Caching
{
"pipeline": {
"dev": {
"cache": false, // No cache in dev mode
"persistent": true
},
"build": {
"cache": true // Cache only builds
}
}
}
Performance Monitoring
Build Analysis
# Detailed logs
turbo run build --verbosity=2
# Timing information
turbo run build --profile=profile.json
# Check cache status
turbo run build --dry-run
Find Bottlenecks
# Check build time per package
turbo run build --graph
# Visualize dependency graph
turbo run build --graph=graph.html
Practical Tips
1. Local Development Optimization
# Build only changed app
turbo run build --filter=web...
# Parallel dev servers
turbo run dev --parallel --filter=web --filter=api
2. CI Optimization
# PR: only changed
turbo run build test --filter=...[origin/main]
# main: full build + cache refresh
turbo run build test
3. Deployment Optimization
# Build and deploy specific app only
turbo run build --filter=web...
cd apps/web && vercel deploy
Summary
5 Optimization Techniques
- Cache Configuration: Perfect
outputssetup → 60x improvement - Dependency Optimization: Remove unnecessary
dependsOn→ 3-5x improvement - Remote Cache: Share cache across team → 50% team-wide savings
- Parallel Execution:
--parallelflag → 2-3x improvement - Filtering: Build only changed → 5x improvement
Overall Impact
Before optimization: 10 minutes
After optimization: 30 seconds (cache hit)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Improvement: 20x faster 🚀🚀🚀
Immediate Action Checklist
Today:
- Set
outputsinturbo.json - Remove unnecessary
dependsOn - Add
--parallelflag This Week: - Connect Remote Cache
- Apply filtering in CI
- Measure and compare build times This Month:
- Roll out Remote Cache team-wide
- Optimize dependency graph
- Build monitoring dashboard
Learn More
- Complete Turborepo Guide - From basics to advanced
- pnpm Workspace Guide - Package manager optimization
- Monorepo Architecture Design - Structure design best practices Dramatically reduce your build time with Turborepo! 🚀
Frequently Asked Questions (FAQ)
Q. When would I use this in practice?
A. A practical optimization guide to reduce Turborepo build time from 10 minutes to 1 minute.
Q. What should I read before this?
A. Follow the previous article or related articles links at the bottom of each post to learn in sequence.
Q. Where can I study this more deeply?
A. Check cppreference and the relevant library’s official documentation. The reference links at the end of the article are also worth using.
Related Articles (Internal Links)
Other articles related to this topic.
- Turborepo 완벽 가이드 | Monorepo·빌드 캐싱·병렬 실행·pnpm·실전 활용
- pnpm Complete Guide
- Docker Compose Complete Guide | Multi-Container Apps
Keywords Covered in This Article (Related Search Terms)
This article covers Turborepo, Monorepo, Performance, Build, Optimization, Cache.