Problem: Monorepo Builds Are Slow and Configuration Is Complex
Your multi-package project takes 10+ minutes to build because every change rebuilds everything. Setting up proper caching and task orchestration feels overwhelming.
You'll learn:
- Configure Turborepo's intelligent caching system
- Set up optimal pipeline dependencies
- Use AI (Claude/ChatGPT) to generate and optimize configs
- Deploy with Remote Caching for team-wide speed
Time: 20 min | Level: Intermediate
Why This Happens
Without a build orchestrator, tools like npm/pnpm workspaces run tasks in parallel but can't:
- Cache outputs intelligently
- Skip unchanged packages
- Understand task dependencies (build before test)
- Share cache across machines
Common symptoms:
- CI rebuilds everything on every commit
- Local builds take 5+ minutes for one-line changes
- Test suites re-run for unrelated package changes
- Team members duplicate build work
Solution
Step 1: Initialize Turborepo
# In existing monorepo root
npx create-turbo@latest --skip-install
# Or start fresh
npx create-turbo@latest my-monorepo
cd my-monorepo
Expected: Creates turbo.json and updates package.json scripts.
If you have existing workspace structure:
npm install turbo --save-dev
# or
pnpm add turbo -Dw
Step 2: Configure Basic Pipeline
Create or edit turbo.json:
{
"$schema": "https://turbo.build/schema.json",
"pipeline": {
"build": {
// Build depends on dependencies being built first
"dependsOn": ["^build"],
// Cache build outputs
"outputs": ["dist/**", ".next/**", "build/**"]
},
"test": {
// Test depends on current package being built
"dependsOn": ["build"],
"outputs": ["coverage/**"]
},
"lint": {
// Lint runs independently
"cache": true
},
"dev": {
// Dev mode never caches
"cache": false,
"persistent": true
}
}
}
Why this works:
^build= "build all dependencies first"outputs= "cache these directories"persistent: true= "keep running (for dev servers)"
Step 3: Use AI to Generate Advanced Config
Instead of manually configuring complex pipelines, use AI assistance:
Prompt for Claude/ChatGPT:
I have a Turborepo monorepo with these packages:
- @myapp/web (Next.js 15, needs: @myapp/ui, @myapp/api-client)
- @myapp/api (Express, needs: @myapp/db, @myapp/types)
- @myapp/ui (React component library)
- @myapp/db (Prisma schemas)
- @myapp/types (Shared TypeScript types)
Generate an optimized turbo.json with:
1. Proper dependency order
2. Prisma generation before builds
3. Type checking in parallel with tests
4. E2E tests only after all builds complete
5. Environment variable handling
Explain each dependsOn choice.
AI-Generated Result:
{
"$schema": "https://turbo.build/schema.json",
"globalEnv": [
"NODE_ENV",
"DATABASE_URL",
"NEXT_PUBLIC_API_URL"
],
"pipeline": {
"db:generate": {
// Prisma client generation has no dependencies
"cache": true,
"outputs": ["node_modules/.prisma/**"]
},
"build": {
// Build after dependencies build AND Prisma generates
"dependsOn": ["^build", "db:generate"],
"outputs": ["dist/**", ".next/**", "build/**"],
"env": ["NODE_ENV"]
},
"type-check": {
// Type check can run parallel to build, just needs types package
"dependsOn": ["^build"],
"outputs": []
},
"test": {
// Tests need current package built, can run parallel to type-check
"dependsOn": ["build"],
"outputs": ["coverage/**"]
},
"test:e2e": {
// E2E needs everything built across entire monorepo
"dependsOn": ["^build", "build"],
"outputs": ["playwright-report/**"],
"cache": false
},
"lint": {
"cache": true,
"outputs": []
},
"dev": {
"dependsOn": ["^build"],
"cache": false,
"persistent": true
}
}
}
Why AI helps:
- Catches subtle dependency issues (Prisma before build)
- Suggests parallel execution opportunities (type-check + test)
- Explains reasoning for complex
dependsOnchains
Step 4: Optimize Package Scripts
AI can also generate package.json script conventions:
Prompt:
Generate package.json scripts for a Next.js app in Turborepo that:
- Uses turbo for all multi-package tasks
- Has local-only dev commands
- Includes proper cleaning
AI Response (edited for clarity):
{
"scripts": {
"dev": "turbo run dev",
"build": "turbo run build",
"test": "turbo run test",
"test:e2e": "turbo run test:e2e",
"lint": "turbo run lint",
"type-check": "turbo run type-check",
"clean": "turbo run clean && rm -rf node_modules/.cache",
"format": "prettier --write \"**/*.{ts,tsx,md}\""
}
}
Step 5: Enable Remote Caching (Optional but Recommended)
For teams, share cache across machines:
# Sign up for Vercel (free tier)
npx turbo login
# Link your repo
npx turbo link
Alternative: Self-hosted cache
Use AI to generate a Docker Compose setup:
Prompt:
Create a docker-compose.yml for self-hosted Turborepo remote cache using turborepo-remote-cache package
AI Result:
version: '3.8'
services:
turbo-cache:
image: fox1t/turborepo-remote-cache:latest
ports:
- "3000:3000"
environment:
TURBO_TOKEN: "your-secret-token-here"
STORAGE_PATH: /cache
volumes:
- turbo-cache-data:/cache
restart: unless-stopped
volumes:
turbo-cache-data:
Then configure in .turbo/config.json:
{
"apiUrl": "http://localhost:3000",
"token": "your-secret-token-here",
"teamId": "team_local"
}
Step 6: Add Task Filtering
Run tasks for specific packages:
# Build only web app and its dependencies
turbo run build --filter=@myapp/web
# Run tests in packages that changed since main branch
turbo run test --filter=[main]
# Build everything except docs
turbo run build --filter=!./apps/docs
Why filtering matters: CI can skip unaffected packages, saving minutes per build.
Step 7: Visualize Your Pipeline
# Generate pipeline graph
npx turbo run build --graph=graph.html
# Open in browser
open graph.html
Use AI to interpret the graph:
Take a screenshot and ask:
[Upload graph.html screenshot]
Are there any inefficiencies in this pipeline?
Can any tasks run in parallel but aren't?
AI can spot issues like:
- Tasks with unnecessary
dependsOnentries - Missing parallelization opportunities
- Circular dependencies
Verification
Test the cache:
# First run (cold cache)
time turbo run build
# Should take full time, e.g. 120 seconds
# Second run (warm cache)
time turbo run build
# Should complete in <2 seconds with "cache hit" messages
You should see:
• Packages in scope: 8
• Running build in 8 packages
• Remote caching enabled
@myapp/types:build: cache hit, replaying logs
@myapp/ui:build: cache hit, replaying logs
@myapp/web:build: cache hit, replaying logs
Tasks: 8 successful, 8 total
Cached: 8 cached, 8 total
Time: 1.2s >>> FULL TURBO
If cache isn't hitting:
- Check: Are you modifying files in
outputsdirectories? Add them to.gitignore - Check: Do you have environment variables in
globalEnvthat change often? - Run:
turbo run build --forceto bypass cache once and rebuild
Advanced: AI-Assisted CI Configuration
Prompt for GitHub Actions:
Create a GitHub Actions workflow for Turborepo monorepo that:
- Uses Remote Caching
- Only builds/tests changed packages
- Deploys web app to Vercel on main branch
- Runs E2E only if web app changed
AI-Generated Workflow:
name: CI
on:
push:
branches: [main]
pull_request:
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 2
- uses: pnpm/action-setup@v2
with:
version: 8
- uses: actions/setup-node@v4
with:
node-version: 22
cache: 'pnpm'
- run: pnpm install --frozen-lockfile
- name: Build and test affected
run: |
pnpm turbo run build test --filter=[HEAD^1]
env:
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
TURBO_TEAM: ${{ secrets.TURBO_TEAM }}
- name: E2E tests if web changed
run: |
if git diff --name-only HEAD^1 | grep -q "apps/web"; then
pnpm turbo run test:e2e --filter=@myapp/web
fi
deploy:
needs: build
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: amondnet/vercel-action@v25
with:
vercel-token: ${{ secrets.VERCEL_TOKEN }}
vercel-org-id: ${{ secrets.VERCEL_ORG_ID }}
vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }}
Common Pitfalls (AI Can Catch These)
1. Missing outputs Directories
Symptom: Cache never hits
AI Fix Prompt:
My Turborepo build task isn't caching. Here's my turbo.json:
[paste config]
And my package.json build script:
"build": "tsc --outDir lib"
What's wrong?
AI Response:
Your build outputs to `lib/` but turbo.json specifies `dist/**`.
Change outputs to ["lib/**"] or update tsconfig to use dist/.
2. Over-Broad Environment Variables
Symptom: Cache invalidates on every build
Bad:
{
"globalEnv": ["*"] // Don't do this!
}
AI-Optimized:
{
"globalEnv": [
"NODE_ENV",
"CI",
"DATABASE_URL"
],
"pipeline": {
"build": {
// Only these vars affect web builds
"env": ["NEXT_PUBLIC_*"]
}
}
}
3. Circular Dependencies
Symptom: turbo run build hangs or errors
AI Debug Prompt:
Turborepo gives "cycle detected" error. Here's my turbo.json:
[paste config]
Help me find the circular dependency.
AI will trace the chain, e.g.:
build → ^build (dependencies build first)
Your @myapp/web depends on @myapp/api
Your @myapp/api depends on @myapp/web
This creates: web → api → web (cycle)
Fix: Split shared code into @myapp/shared package.
Performance Benchmarks
Real-world example (12 packages, Next.js + Node.js):
| Scenario | Without Turbo | With Turbo | Savings |
|---|---|---|---|
| Full build (cold) | 8m 20s | 8m 15s | ~5s |
| Full build (warm cache) | 8m 20s | 2.1s | 99.6% |
| Changed 1 package | 8m 20s | 35s | 93% |
| CI (changed 2 packages) | 8m 20s | 48s | 90% |
| Lint only | 45s | 0.8s | 98% |
Cumulative team savings:
- 20 devs × 10 builds/day × 7 min saved = 23 hours/day
- CI: 50 builds/day × 7 min saved = 6 hours/day
What You Learned
- Turborepo caches task outputs, not just files
dependsOncontrols execution order and cache invalidation- AI tools excel at generating complex pipeline configs
- Remote caching multiplies benefits across team
- Filtering prevents unnecessary work in CI
Limitations:
- Cache storage grows (prune with
turbo prune) - First-time setup requires understanding package relationships
- Remote cache needs network connectivity
AI Prompting Cheatsheet
For Configuration:
Generate turbo.json for [describe packages] with [requirements]
For Debugging:
Why isn't Turborepo caching my [task]?
Here's my turbo.json: [paste]
Here's my package.json script: [paste]
For CI:
Create [CI platform] workflow for Turborepo with [requirements]
For Optimization:
Review this turbo.json and suggest optimizations: [paste]
For Migration:
Convert this Lerna setup to Turborepo: [paste lerna.json]
Troubleshooting
Cache Not Working
# Check what turbo sees
turbo run build --dry-run
# Force rebuild and re-cache
turbo run build --force
# Check for .turbo in each package
find . -type d -name ".turbo"
Slow Builds Despite Cache
# Profile where time is spent
turbo run build --profile=profile.json
# Visualize profile
npx turbo-profile profile.json
Remote Cache Connection Issues
# Test connection
curl https://api.vercel.com/v8/artifacts/status \
-H "Authorization: Bearer $TURBO_TOKEN"
# Check .turbo/config.json is valid
cat .turbo/config.json | jq
Tested on Turborepo 2.0.3, Node.js 22.x, pnpm 8.15, macOS/Ubuntu/Windows
Resource links: