turborepo
Turborepo
Turborepo is a high-performance build system for JavaScript/TypeScript monorepos. It provides intelligent caching, parallel execution, and incremental builds.
Core Concepts
Monorepo Structure
my-turborepo/
├── apps/
│ ├── web/ # Next.js app
│ │ ├── package.json
│ │ └── next.config.js
│ └── docs/ # Documentation site
│ └── package.json
├── packages/
│ ├── ui/ # Shared component library
│ │ ├── package.json
│ │ └── src/
│ ├── config/ # Shared configs (ESLint, TS, etc.)
│ │ └── package.json
│ └── utils/ # Shared utilities
│ └── package.json
├── turbo.json # Turborepo configuration
├── package.json # Root package.json
└── pnpm-workspace.yaml # Workspace definition
turbo.json Configuration
{
"$schema": "https://turborepo.com/schema.json",
"ui": "stream",
"envMode": "strict",
"tasks": {
"build": {
"dependsOn": ["^build"],
"inputs": ["$TURBO_DEFAULT$", ".env*"],
"outputs": [".next/**", "!.next/cache/**", "dist/**"],
"env": ["NODE_ENV", "DATABASE_URL", "NEXT_PUBLIC_*"]
},
"dev": {
"cache": false,
"persistent": true,
"interactive": true
},
"lint": {
"dependsOn": ["^build"],
"outputs": []
},
"test": {
"dependsOn": ["build"],
"inputs": ["src/**", "test/**"],
"outputs": ["coverage/**"]
},
"typecheck": {
"dependsOn": ["^build"],
"outputs": []
}
}
}
Workspace Package.json
{
"name": "my-turborepo",
"private": true,
"scripts": {
"build": "turbo run build",
"dev": "turbo run dev",
"lint": "turbo run lint",
"test": "turbo run test",
"typecheck": "turbo run typecheck",
"clean": "turbo run clean && rm -rf node_modules"
},
"devDependencies": {
"turbo": "^2.7.2"
},
"packageManager": "pnpm@10.26.0"
}
pnpm-workspace.yaml
packages:
- 'apps/*'
- 'packages/*'
Task Configuration
Dependency Types
{
"tasks": {
// Topological dependency (dependencies first)
"build": {
"dependsOn": ["^build"] // Run build in all dependencies first
},
// Same-package dependency
"test": {
"dependsOn": ["build"] // Run build in same package first
},
// Cross-package specific dependency
"deploy": {
"dependsOn": ["build", "test", "^build"]
},
// Arbitrary package#task dependency
"e2e": {
"dependsOn": ["web#build", "api#build"] // Specific packages
}
}
}
Input/Output Configuration
{
"tasks": {
"build": {
// Files that affect cache
"inputs": [
"$TURBO_DEFAULT$", // Default: all non-gitignored files
"!README.md", // Exclude README changes
".env.production", // Include specific env file
"$TURBO_ROOT$/tsconfig.json" // Reference files from repo root
],
// Files produced by task
"outputs": [
"dist/**",
".next/**",
"!.next/cache/**" // Exclude .next/cache
]
}
}
}
Note: The following files are always considered inputs and cannot be ignored:
package.jsonturbo.json- Package manager lockfiles (automatically included in global hash)
Environment Variables
{
"globalEnv": ["CI", "VERCEL"],
"globalPassThroughEnv": ["AWS_ACCESS_KEY"],
"tasks": {
"build": {
"env": [
"DATABASE_URL",
"NEXT_PUBLIC_*", // Wildcard: all vars starting with NEXT_PUBLIC_
"!GITHUB_*" // Negation: exclude GITHUB_ vars from strict mode
],
"passThroughEnv": ["AWS_SECRET_KEY"] // Available but not in cache hash
}
}
}
Caching
Local Caching
# Cache stored in node_modules/.cache/turbo
turbo run build
# Force cache miss
turbo run build --force
Remote Caching
# Login to Vercel Remote Cache
npx turbo login
# Link project
npx turbo link
# Or use custom cache server
TURBO_API="https://cache.example.com"
TURBO_TOKEN="your-token"
TURBO_TEAM="your-team"
Cache Configuration
{
"tasks": {
"build": {
"cache": true, // Enable caching (default)
"outputLogs": "new-only" // Show logs only on cache miss
},
"dev": {
"cache": false, // Disable caching for dev
"persistent": true, // Long-running task
"interactive": true // Accepts keyboard input (stdin)
},
"db:studio": {
"cache": false,
"persistent": true,
"interruptible": true // Can be restarted when dependencies change
}
}
}
Development Mode
turbo watch
Re-run tasks automatically when files change:
# Watch all tasks
turbo watch build lint typecheck
# Watch specific packages
turbo watch build --filter=web
# Write cache in watch mode (experimental)
turbo watch build --experimental-write-cache
Watch mode is dependency-aware - when a package changes, all dependent packages re-run their tasks. Persistent tasks (dev servers) are automatically handled.
Docker Optimization
turbo prune
Generate a partial monorepo for efficient Docker builds:
# Basic prune
turbo prune web
# Docker-optimized output (recommended)
turbo prune web --docker
The --docker flag creates:
out/json/- package.json files only (for dependency layer)out/full/- Complete pruned workspace (for build layer)
Dockerfile Pattern
FROM node:22-alpine AS builder
WORKDIR /app
# Install turbo globally
RUN npm install -g turbo
# Copy all files and prune
COPY . .
RUN turbo prune web --docker
# Install dependencies (cached layer)
FROM node:22-alpine AS installer
WORKDIR /app
COPY /app/out/json/ .
RUN npm install
# Build the app
COPY /app/out/full/ .
RUN npx turbo run build --filter=web
# Production image
FROM node:22-alpine AS runner
WORKDIR /app
COPY /app/apps/web/.next/standalone ./
COPY /app/apps/web/.next/static ./apps/web/.next/static
COPY /app/apps/web/public ./apps/web/public
CMD ["node", "apps/web/server.js"]
Filtering
Package Filters
# Run build only in web app
turbo run build --filter=web
# Run in web and its dependencies
turbo run build --filter=web...
# Run in packages that depend on ui
turbo run build --filter=...^ui
# Target specific task in specific package
turbo run web#lint
Source Control Filters
# Packages changed since main branch
turbo run build --filter=[main...my-feature]
# Packages changed since previous commit
turbo run build --filter=[HEAD^1]
# Packages changed between specific commits
turbo run build --filter=[a1b2c3d...e4f5g6h]
# Build all packages depending on changes in branch
turbo run build --filter=...[origin/my-feature]
# Combine package and source control filters
turbo run build --filter=@acme/ui...[HEAD^1]
turbo run test --filter=@acme/*{./packages/*}[HEAD^1]
Affected Flag (CI Optimized)
# Run only on packages with code changes (auto-detects CI environment)
turbo run build --affected
# Override comparison branches via environment
TURBO_SCM_BASE=main TURBO_SCM_HEAD=HEAD turbo run build --affected
Workspace Filters
# All apps
turbo run build --filter="./apps/*"
# All packages
turbo run build --filter="./packages/*"
# Exclude specific package
turbo run build --filter=./apps/* --filter=!./apps/admin
# Multiple specific packages
turbo run build --filter=docs --filter=web
Package Configuration
Internal Package (packages/ui/package.json)
{
"name": "@repo/ui",
"version": "0.0.0",
"private": true,
"exports": {
".": "./src/index.tsx",
"./button": "./src/button.tsx",
"./card": "./src/card.tsx"
},
"scripts": {
"build": "tsup",
"lint": "eslint src/",
"typecheck": "tsc --noEmit"
},
"devDependencies": {
"@repo/config": "workspace:*",
"typescript": "^5.0.0"
}
}
App Package (apps/web/package.json)
{
"name": "web",
"version": "0.0.0",
"private": true,
"scripts": {
"build": "next build",
"dev": "next dev",
"lint": "next lint",
"start": "next start"
},
"dependencies": {
"@repo/ui": "workspace:*",
"@repo/utils": "workspace:*",
"next": "^16.1.1",
"react": "^19.0.0"
}
}
CI/CD Integration
GitHub Actions
name: CI
on:
push:
branches: [main]
pull_request:
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # Full history for --affected flag
- uses: pnpm/action-setup@v4
with:
version: 10
- uses: actions/setup-node@v4
with:
node-version: 22
cache: 'pnpm'
- run: pnpm install --frozen-lockfile
# Option 1: Run all tasks with remote caching
- run: pnpm turbo run build lint test
env:
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
TURBO_TEAM: ${{ vars.TURBO_TEAM }}
# Option 2: Run only affected packages (optimized for large repos)
- run: pnpm turbo run build lint test --affected
env:
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
TURBO_TEAM: ${{ vars.TURBO_TEAM }}
Best Practices
- Keep packages focused - Single responsibility
- Use workspace protocol -
workspace:*for internal deps - Share configs - Put ESLint, TS config in packages/config
- Cache aggressively - Remote caching for CI
- Filter in CI - Only build what changed
References
- references/configuration.md - Full config reference
- references/filters.md - Filter patterns
More from fractionestate/midnight-dev-skills
tailwindcss
>-
24nextjs
Next.js 16.1+ App Router patterns including Server Components, Client Components, Server Actions, Route Handlers, Turbopack, MCP integration, and modern React patterns. Use when building pages, layouts, data fetching, or API routes. Triggers on Next.js, App Router, RSC, or Server Actions questions.
5playwright
>-
5prisma
>-
4security
Security auditing patterns for Midnight Network smart contracts and dApps. Use when reviewing code for vulnerabilities, privacy leaks, cryptographic weaknesses, or performing security audits.
4compact
>-
4