Turborepo Skill
Turborepo is a high-performance build system optimized for JavaScript and TypeScript monorepos, written in Rust. It provides intelligent caching, task orchestration, and remote execution capabilities to dramatically speed up development workflows.
Reference
https://turborepo.com/llms.txt
When to Use This Skill
Use this skill when:
- •Setting up a new monorepo with multiple packages
- •Optimizing build performance in existing monorepos
- •Implementing task pipelines across packages
- •Configuring intelligent caching strategies
- •Setting up remote caching for teams
- •Orchestrating tasks with dependency awareness
- •Integrating monorepo with CI/CD pipelines
- •Migrating from Lerna, Nx, or other monorepo tools
- •Building microfrontends or shared libraries
- •Managing workspace dependencies
Core Concepts
1. Monorepo Architecture
Turborepo organizes code into packages within a single repository:
- •Root Package: Contains workspace configuration
- •Internal Packages: Shared libraries, utilities, configs
- •Applications: Frontend apps, backend services, etc.
- •Workspaces: npm/yarn/pnpm workspace configuration
2. Task Pipeline
Tasks are organized in a dependency graph:
- •Task Dependencies: Define execution order (build before test)
- •Package Dependencies: Respect internal package relationships
- •Parallel Execution: Run independent tasks simultaneously
- •Topological Ordering: Execute tasks in correct dependency order
3. Intelligent Caching
Turborepo caches task outputs based on inputs:
- •Local Cache: Stores outputs on local machine
- •Remote Cache: Shares cache across team/CI (Vercel or custom)
- •Content-Based Hashing: Only re-run when inputs change
- •Cache Restoration: Instant task completion from cache
4. Task Outputs
Define what gets cached:
- •Build artifacts (dist/, build/)
- •Test results
- •Generated files
- •Type definitions
Installation
Prerequisites
# Requires Node.js 18+ and a package manager node --version # v18.0.0+
Global Installation
# npm npm install turbo --global # yarn yarn global add turbo # pnpm pnpm add turbo --global # bun bun add turbo --global
Per-Project Installation
# npm npm install turbo --save-dev # yarn yarn add turbo --dev # pnpm pnpm add turbo --save-dev # bun bun add turbo --dev
Project Setup
Create New Monorepo
Using official examples:
npx create-turbo@latest
Interactive prompts will ask:
- •Project name
- •Package manager (npm/yarn/pnpm/bun)
- •Example template selection
Manual Setup
1. Initialize workspace:
// package.json (root)
{
"name": "my-turborepo",
"private": true,
"workspaces": ["apps/*", "packages/*"],
"scripts": {
"build": "turbo run build",
"dev": "turbo run dev",
"test": "turbo run test",
"lint": "turbo run lint"
},
"devDependencies": {
"turbo": "latest"
}
}
2. Create directory structure:
my-turborepo/ ├── apps/ │ ├── web/ # Next.js app │ └── docs/ # Documentation site ├── packages/ │ ├── ui/ # Shared UI components │ ├── config/ # Shared configs (ESLint, TS) │ └── tsconfig/ # Shared TypeScript configs ├── turbo.json # Turborepo configuration └── package.json # Root package.json
3. Create turbo.json:
{
"$schema": "https://turbo.build/schema.json",
"globalDependencies": ["**/.env.*local"],
"pipeline": {
"build": {
"dependsOn": ["^build"],
"outputs": [".next/**", "!.next/cache/**", "dist/**"]
},
"dev": {
"cache": false,
"persistent": true
},
"lint": {},
"test": {
"dependsOn": ["build"]
}
}
}
Configuration (turbo.json)
Basic Structure
{
"$schema": "https://turbo.build/schema.json",
"globalDependencies": [".env", "tsconfig.json"],
"globalEnv": ["NODE_ENV"],
"pipeline": {
// Task definitions
}
}
Pipeline Configuration
Task with dependencies:
{
"pipeline": {
"build": {
"dependsOn": ["^build"],
"outputs": ["dist/**", ".next/**"],
"env": ["NODE_ENV", "API_URL"]
}
}
}
Key properties:
- •
dependsOn: Tasks to run first- •
["^build"]: Run dependencies' build first - •
["build"]: Run own build first - •
["^build", "lint"]: Run deps' build and own lint
- •
- •
outputs: Files/directories to cache - •
inputs: Override input detection (default: all tracked files) - •
cache: Enable/disable caching (default: true) - •
env: Environment variables that affect output - •
persistent: Keep task running (for dev servers) - •
outputMode: Control output display
Task Dependency Patterns
Topological (^):
{
"build": {
"dependsOn": ["^build"] // Run dependencies' build first
}
}
Regular:
{
"deploy": {
"dependsOn": ["build", "test"] // Run own build and test first
}
}
Combined:
{
"test": {
"dependsOn": ["^build", "lint"] // Deps' build, then own lint
}
}
Output Modes
{
"pipeline": {
"build": {
"outputMode": "full" // Show all output
},
"dev": {
"outputMode": "hash-only" // Show cache hash only
},
"test": {
"outputMode": "new-only" // Show new output only
},
"lint": {
"outputMode": "errors-only" // Show errors only
}
}
}
Environment Variables
Global environment variables:
{
"globalEnv": ["NODE_ENV", "CI"],
"globalDependencies": [".env", ".env.local"]
}
Per-task environment variables:
{
"pipeline": {
"build": {
"env": ["NEXT_PUBLIC_API_URL", "DATABASE_URL"],
"passThroughEnv": ["CUSTOM_VAR"] // Pass without hashing
}
}
}
Commands
turbo run
Run tasks across packages:
# Run build in all packages turbo run build # Run multiple tasks turbo run build test lint # Run in specific packages turbo run build --filter=web turbo run build --filter=@myorg/ui # Run in packages matching pattern turbo run build --filter='./apps/*' # Force execution (skip cache) turbo run build --force # Run from specific directory turbo run build --filter='[./apps/web]' # Run with dependencies turbo run build --filter='...^web' # Parallel execution control turbo run build --concurrency=3 turbo run build --concurrency=50% # Continue on error turbo run test --continue # Dry run turbo run build --dry-run # Output control turbo run build --output-logs=new-only turbo run build --output-logs=hash-only turbo run build --output-logs=errors-only turbo run build --output-logs=full
turbo prune
Create a subset of the monorepo:
# Prune for specific app turbo prune --scope=web # Prune with Docker turbo prune --scope=api --docker # Output to custom directory turbo prune --scope=web --out-dir=./deploy
Use cases:
- •Docker builds (only include necessary packages)
- •Deploy specific apps
- •Reduce CI/CD context size
turbo gen
Generate code in your monorepo:
# Generate new package turbo gen workspace # Generate from custom generator turbo gen my-generator # List available generators turbo gen --list
turbo link
Link local repo to remote cache:
# Link to Vercel turbo link # Unlink turbo unlink
turbo login
Authenticate with Vercel:
turbo login
turbo ls
List packages in monorepo:
# List all packages turbo ls # JSON output turbo ls --json
Filtering
Filter by Package Name
# Single package turbo run build --filter=web # Multiple packages turbo run build --filter=web --filter=api # Scoped package turbo run build --filter=@myorg/ui
Filter by Pattern
# All apps turbo run build --filter='./apps/*' # Pattern matching turbo run build --filter='*-ui'
Filter by Directory
# From specific directory turbo run build --filter='[./apps/web]'
Filter by Git
# Changed since main turbo run build --filter='[main]' # Changed since HEAD~1 turbo run build --filter='[HEAD~1]' # Changed in working directory turbo run test --filter='...[HEAD]'
Filter by Dependencies
# Package and its dependencies turbo run build --filter='...web' # Package's dependencies only turbo run build --filter='...^web' # Package and its dependents turbo run test --filter='ui...' # Package's dependents only turbo run test --filter='^ui...'
Caching Strategies
Local Caching
Enabled by default, stores in ./node_modules/.cache/turbo
Cache behavior:
{
"pipeline": {
"build": {
"outputs": ["dist/**"], // Cache dist directory
"cache": true // Enable caching (default)
},
"dev": {
"cache": false // Disable for dev servers
}
}
}
Clear cache:
# Clear Turbo cache rm -rf ./node_modules/.cache/turbo # Or use turbo command turbo run build --force # Skip cache for this run
Remote Caching
Share cache across team and CI:
1. Link to Vercel (recommended):
turbo login turbo link
2. Custom remote cache:
// .turbo/config.json
{
"teamid": "team_123",
"apiurl": "https://cache.example.com",
"token": "your-token"
}
Benefits:
- •Share builds across team
- •Speed up CI/CD
- •Consistent builds
- •Reduce compute costs
Cache Signatures
Cache is invalidated when:
- •Source files change
- •Dependencies change
- •Environment variables change (if specified)
- •Global dependencies change
- •Task configuration changes
Control inputs:
{
"pipeline": {
"build": {
"inputs": ["src/**/*.ts", "!src/**/*.test.ts"],
"env": ["NODE_ENV"]
}
}
}
Workspace Patterns
Package Types
1. Internal packages (packages/*):
// packages/ui/package.json
{
"name": "@myorg/ui",
"version": "0.0.0",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
"scripts": {
"build": "tsc",
"dev": "tsc --watch",
"lint": "eslint ."
}
}
2. Applications (apps/*):
// apps/web/package.json
{
"name": "web",
"version": "1.0.0",
"private": true,
"dependencies": {
"@myorg/ui": "*",
"next": "latest"
},
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start"
}
}
Dependency Management
Workspace protocol (pnpm/yarn):
{
"dependencies": {
"@myorg/ui": "workspace:*"
}
}
Version protocol (npm):
{
"dependencies": {
"@myorg/ui": "*"
}
}
Shared Configuration
ESLint config package:
// packages/eslint-config/index.js
module.exports = {
extends: ["next", "prettier"],
rules: {
// shared rules
}
}
TypeScript config package:
// packages/tsconfig/base.json
{
"compilerOptions": {
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
}
}
Usage:
// apps/web/tsconfig.json
{
"extends": "@myorg/tsconfig/base.json",
"compilerOptions": {
"jsx": "preserve"
}
}
CI/CD Integration
GitHub Actions
name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 18
- name: Install dependencies
run: npm install
- name: Build
run: npx turbo run build
env:
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
TURBO_TEAM: ${{ secrets.TURBO_TEAM }}
- name: Test
run: npx turbo run test
GitLab CI
image: node:18
cache:
key: ${CI_COMMIT_REF_SLUG}
paths:
- node_modules/
- .turbo/
build:
stage: build
script:
- npm install
- npx turbo run build
variables:
TURBO_TOKEN: $TURBO_TOKEN
TURBO_TEAM: $TURBO_TEAM
Docker
FROM node:18-alpine AS base # Prune workspace FROM base AS builder RUN npm install -g turbo COPY . . RUN turbo prune --scope=web --docker # Install dependencies FROM base AS installer COPY --from=builder /app/out/json/ . COPY --from=builder /app/out/package-lock.json ./package-lock.json RUN npm install # Build COPY --from=builder /app/out/full/ . RUN npx turbo run build --filter=web # Runner FROM base AS runner COPY --from=installer /app/apps/web/.next/standalone ./ COPY --from=installer /app/apps/web/.next/static ./apps/web/.next/static COPY --from=installer /app/apps/web/public ./apps/web/public CMD node apps/web/server.js
Optimization Tips
- •Use remote caching in CI:
env:
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
TURBO_TEAM: ${{ secrets.TURBO_TEAM }}
- •Cache node_modules:
- uses: actions/cache@v3
with:
path: node_modules
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
- •Run only affected tasks:
turbo run build test --filter='...[origin/main]'
Framework Integration
Next.js
// apps/web/package.json
{
"name": "web",
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start"
},
"dependencies": {
"next": "latest",
"react": "latest"
}
}
turbo.json:
{
"pipeline": {
"build": {
"outputs": [".next/**", "!.next/cache/**"]
},
"dev": {
"cache": false,
"persistent": true
}
}
}
Vite
{
"pipeline": {
"build": {
"dependsOn": ["^build"],
"outputs": ["dist/**"]
},
"dev": {
"cache": false,
"persistent": true
}
}
}
NuxtJS
{
"pipeline": {
"build": {
"outputs": [".output/**", ".nuxt/**"]
},
"dev": {
"cache": false,
"persistent": true
}
}
}
Development Tools Integration
TypeScript
{
"pipeline": {
"build": {
"dependsOn": ["^build"],
"outputs": ["dist/**", "*.tsbuildinfo"]
},
"typecheck": {
"dependsOn": ["^build"]
}
}
}
ESLint
{
"pipeline": {
"lint": {
"dependsOn": ["^build"],
"outputs": []
}
}
}
Jest / Vitest
{
"pipeline": {
"test": {
"dependsOn": ["build"],
"outputs": ["coverage/**"],
"cache": true
}
}
}
Prisma
{
"pipeline": {
"db:generate": {
"cache": false
},
"db:push": {
"cache": false
}
}
}
Best Practices
1. Structure Your Monorepo
my-monorepo/ ├── apps/ # Applications │ ├── web/ # Frontend app │ ├── api/ # Backend API │ └── docs/ # Documentation ├── packages/ # Shared packages │ ├── ui/ # UI components │ ├── config/ # Shared configs │ ├── utils/ # Utilities │ └── tsconfig/ # TS configs ├── tooling/ # Development tools │ ├── eslint-config/ │ └── prettier-config/ └── turbo.json
2. Define Clear Task Dependencies
{
"pipeline": {
"build": {
"dependsOn": ["^build"]
},
"test": {
"dependsOn": ["build"]
},
"lint": {
"dependsOn": ["^build"]
},
"deploy": {
"dependsOn": ["build", "test", "lint"]
}
}
}
3. Optimize Cache Configuration
- •Cache build outputs, not source files
- •Include all generated files in outputs
- •Exclude cache directories (e.g.,
.next/cache) - •Disable cache for dev servers
{
"pipeline": {
"build": {
"outputs": [
"dist/**",
".next/**",
"!.next/cache/**",
"storybook-static/**"
]
},
"dev": {
"cache": false,
"persistent": true
}
}
}
4. Use Environment Variables Wisely
{
"globalEnv": ["NODE_ENV", "CI"],
"pipeline": {
"build": {
"env": ["NEXT_PUBLIC_API_URL"],
"passThroughEnv": ["DEBUG"] // Don't affect cache
}
}
}
5. Leverage Remote Caching
- •Enable for all team members
- •Configure in CI/CD
- •Reduces build times significantly
- •Especially beneficial for large teams
6. Use Filters Effectively
# Build only changed packages turbo run build --filter='...[origin/main]' # Build specific app with dependencies turbo run build --filter='...web' # Test only affected packages turbo run test --filter='...[HEAD^1]'
7. Organize Scripts Consistently
Root package.json:
{
"scripts": {
"build": "turbo run build",
"dev": "turbo run dev",
"lint": "turbo run lint",
"test": "turbo run test",
"clean": "turbo run clean && rm -rf node_modules"
}
}
8. Handle Persistent Tasks
{
"pipeline": {
"dev": {
"cache": false,
"persistent": true // Keeps running
}
}
}
Common Patterns
Full-Stack Application
apps/
├── web/ # Next.js frontend
│ └── package.json
├── api/ # Express backend
│ └── package.json
└── mobile/ # React Native
└── package.json
packages/
├── ui/ # Shared UI components
├── database/ # Database client/migrations
├── types/ # Shared TypeScript types
└── config/ # Shared configs
Shared Component Library
packages/
├── ui/ # Component library
│ ├── src/
│ ├── package.json
│ └── tsconfig.json
└── ui-docs/ # Storybook
├── .storybook/
├── stories/
└── package.json
Microfrontends
apps/ ├── shell/ # Container app ├── dashboard/ # Dashboard MFE └── settings/ # Settings MFE packages/ ├── shared-ui/ # Shared components └── router/ # Routing logic
Troubleshooting
Cache Issues
Problem: Task not using cache when it should
# Check what's causing cache miss turbo run build --dry-run=json # Force rebuild turbo run build --force # Clear cache rm -rf ./node_modules/.cache/turbo
Problem: Cache too large
# Limit cache size in turbo.json
{
"cacheDir": ".turbo",
"cacheSize": "50gb"
}
Dependency Issues
Problem: Internal package not found
# Ensure workspace is set up correctly npm install # Check package names match npm ls @myorg/ui # Rebuild dependencies turbo run build --filter='...web'
Task Execution Issues
Problem: Tasks running in wrong order
- •Check
dependsOnconfiguration - •Use
^taskfor dependency tasks - •Verify task names match package.json scripts
Problem: Dev server not starting
{
"pipeline": {
"dev": {
"cache": false,
"persistent": true // Add this
}
}
}
Performance Issues
Problem: Builds taking too long
# Run with concurrency limit turbo run build --concurrency=2 # Use filters to build less turbo run build --filter='...[origin/main]' # Check for unnecessary dependencies turbo run build --dry-run
Problem: Remote cache not working
# Verify authentication turbo link # Check environment variables echo $TURBO_TOKEN echo $TURBO_TEAM # Test connection turbo run build --output-logs=hash-only
Migration Guide
From Lerna
- •Replace Lerna with Turborepo:
npm uninstall lerna npm install turbo --save-dev
- •Convert lerna.json to turbo.json:
{
"pipeline": {
"build": {
"dependsOn": ["^build"]
}
}
}
- •Update scripts:
{
"scripts": {
"build": "turbo run build",
"test": "turbo run test"
}
}
From Nx
- •Install Turborepo:
npm install turbo --save-dev
- •Convert nx.json to turbo.json:
- •Map targetDefaults to pipeline
- •Convert dependsOn syntax
- •Configure caching
- •Update workspace configuration
- •Migrate CI/CD scripts
Resources
- •Documentation: https://turbo.build/repo/docs
- •Examples: https://github.com/vercel/turbo/tree/main/examples
- •Discord: https://turbo.build/discord
- •GitHub: https://github.com/vercel/turbo
Implementation Checklist
When setting up Turborepo:
- • Install Turborepo globally or per-project
- • Set up workspace structure (apps/, packages/)
- • Create turbo.json with pipeline configuration
- • Define task dependencies (build, test, lint)
- • Configure cache outputs for each task
- • Set up global dependencies and environment variables
- • Link to remote cache (Vercel or custom)
- • Configure CI/CD integration
- • Add filtering strategies for large repos
- • Document monorepo structure for team
- • Set up code generation (turbo gen)
- • Configure Docker builds with turbo prune
- • Test caching behavior locally
- • Verify remote cache in CI
- • Optimize concurrency settings