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
- 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
- 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
- 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
- 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
- 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" } }
- 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
- 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:
- Link to Vercel (recommended):
turbo login turbo link
- 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
- 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 ." } }
- 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
- 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
- Define Clear Task Dependencies
{ "pipeline": { "build": { "dependsOn": ["^build"] }, "test": { "dependsOn": ["build"] }, "lint": { "dependsOn": ["^build"] }, "deploy": { "dependsOn": ["build", "test", "lint"] } } }
- 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 } } }
- Use Environment Variables Wisely
{ "globalEnv": ["NODE_ENV", "CI"], "pipeline": { "build": { "env": ["NEXT_PUBLIC_API_URL"], "passThroughEnv": ["DEBUG"] // Don't affect cache } } }
- Leverage Remote Caching
-
Enable for all team members
-
Configure in CI/CD
-
Reduces build times significantly
-
Especially beneficial for large teams
- 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]'
- 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" } }
- 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 dependsOn configuration
-
Use ^task for 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