turborepo
GitHub管理JavaScript/TypeScript单体仓库,负责任务编排、缓存及工作区配置。适用于涉及Turbo、monorepo构建、pnpm/npm工作区共享包或多包管理的场景。
Trigger Scenarios
Install
npx skills add NeverSight/learn-skills.dev --skill turborepo -g -y
SKILL.md
Frontmatter
{
"name": "turborepo",
"description": "Turborepo for monorepo management — task orchestration, caching, and workspace configuration. Use when user mentions \"turborepo\", \"turbo\", \"monorepo\", \"workspace\", \"turbo.json\", \"pnpm workspaces\", \"npm workspaces\", \"shared packages\", \"monorepo build\", or managing multiple packages in one repository."
}
Turborepo
Build system for JavaScript/TypeScript monorepos. Handles task orchestration, caching, and dependency-aware execution across workspaces.
Setup
# New monorepo
npx create-turbo@latest my-monorepo
# Add to existing repo
pnpm add turbo --save-dev --workspace-root
# or: npm install turbo --save-dev
Add .turbo to .gitignore. Add root scripts:
{
"scripts": {
"build": "turbo run build",
"dev": "turbo run dev",
"test": "turbo run test",
"lint": "turbo run lint"
}
}
turbo.json Configuration
{
"$schema": "https://turbo.build/schema.json",
"tasks": {
"build": {
"dependsOn": ["^build"],
"outputs": ["dist/**", ".next/**", "build/**"],
"env": ["NODE_ENV"]
},
"test": {
"dependsOn": ["build"],
"outputs": [],
"env": ["CI"]
},
"lint": { "outputs": [] },
"dev": { "cache": false, "persistent": true },
"typecheck": { "dependsOn": ["^build"], "outputs": [] }
}
}
dependsOn-- tasks that must complete first.^prefix = topological (upstream workspaces).outputs-- files produced by the task, used for caching.cache-- setfalseto disable caching.persistent-- marks long-running tasks (dev servers).env-- environment variables that affect the task hash.
Turborepo v2 uses "tasks" instead of the v1 "pipeline" key.
Workspace Structure
my-monorepo/
turbo.json
package.json
pnpm-workspace.yaml
apps/
web/package.json
api/package.json
packages/
ui/package.json
shared-types/package.json
eslint-config/package.json
tsconfig/package.json
Task Orchestration
turbo run build # all workspaces
turbo run lint build test # multiple tasks
turbo run build --concurrency=4 # limit parallelism
turbo run build --concurrency=50% # percentage of CPU cores
Turbo analyzes the dependency graph and parallelizes where possible.
Task Dependencies
"^build" means run build in all upstream workspace dependencies first. If apps/web depends on packages/ui, then packages/ui#build runs before apps/web#build.
"lint" (no caret) means run lint in the same workspace first:
{ "test": { "dependsOn": ["lint", "build"] } }
Per-workspace overrides -- add a turbo.json in the workspace directory:
{
"extends": ["//"],
"tasks": { "build": { "outputs": [".next/**"] } }
}
Caching
Turbo hashes inputs (source files, deps, env vars, config) and caches task outputs. On a cache hit, outputs are restored and logs replayed without re-execution.
turbo run build --no-cache # skip reading cache
turbo run build --force # ignore cache, re-execute all
Remote caching
npx turbo login
npx turbo link
Connects to Vercel for shared remote caching across team members and CI.
Self-hosted endpoint:
turbo run build --api="https://cache.example.com" --token="<token>"
Environment Variables
{
"tasks": {
"build": {
"env": ["API_URL", "DATABASE_URL"],
"passThroughEnv": ["AWS_SECRET_ACCESS_KEY"]
}
},
"globalEnv": ["CI", "VERCEL"]
}
env-- affects this task's cache hash.globalEnv-- affects all tasks' cache hashes.passThroughEnv-- passed to task but excluded from hash (for secrets).
Filtering
turbo run build --filter=web # by workspace name
turbo run build --filter=@myorg/ui # by package name
turbo run test --filter=./apps/* # by path glob
turbo run build --filter=...@myorg/ui # package and its dependents
turbo run build --filter=@myorg/ui... # package and its dependencies
turbo run build --filter=...[HEAD~1] # changed since last commit
turbo run test --filter=...[main...HEAD] # changed vs main branch
turbo run build --filter=./apps/* --filter=!./apps/admin # exclude
Shared Packages
Internal UI library
packages/ui/package.json:
{
"name": "@myorg/ui",
"main": "./src/index.ts",
"types": "./src/index.ts",
"scripts": {
"build": "tsup src/index.ts --format esm,cjs --dts",
"lint": "eslint src/"
}
}
Consume with "@myorg/ui": "workspace:*" in the app's dependencies. For internal packages transpiled by the consuming bundler, point main at TypeScript source and skip the build step.
Shared TypeScript config
packages/tsconfig/base.json:
{
"compilerOptions": {
"strict": true, "target": "ES2020", "module": "ESNext",
"moduleResolution": "bundler", "declaration": true,
"esModuleInterop": true, "skipLibCheck": true
}
}
Reference: { "extends": "@myorg/tsconfig/base.json", "include": ["src"] }
Shared types
packages/shared-types/package.json -- set "main" and "types" to "./src/index.ts". No build step needed if consumers transpile directly.
pnpm Workspaces Integration
pnpm-workspace.yaml:
packages:
- "apps/*"
- "packages/*"
Use workspace:* protocol for internal deps. For npm workspaces, use the "workspaces" field in root package.json instead.
Watch Mode
turbo watch dev
turbo watch build
Watches for file changes, re-runs affected tasks respecting the dependency graph. Shared package changes trigger downstream rebuilds.
Pruning for Docker
turbo prune web --docker
Produces out/json/ (pruned package.json files for install layer) and out/full/ (pruned source).
FROM node:20-alpine AS builder
RUN corepack enable
WORKDIR /app
COPY . .
RUN turbo prune web --docker
FROM node:20-alpine AS installer
RUN corepack enable
WORKDIR /app
COPY --from=builder /app/out/json/ .
RUN pnpm install --frozen-lockfile
COPY --from=builder /app/out/full/ .
RUN turbo run build --filter=web
FROM node:20-alpine AS runner
WORKDIR /app
COPY --from=installer /app/apps/web/.next/standalone ./
CMD ["node", "apps/web/server.js"]
CI/CD Patterns
GitHub Actions with remote cache
name: CI
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
with: { node-version: 20, cache: pnpm }
- run: pnpm install --frozen-lockfile
- run: turbo run build test lint
env:
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
TURBO_TEAM: ${{ vars.TURBO_TEAM }}
Run only affected tasks: turbo run build test --filter=...[origin/main...HEAD]
Use turbo run build --dry-run=json to get the task graph for dispatching parallel CI jobs per workspace.
Migration from Lerna or Nx
From Lerna
- Remove
lerna.jsonandlernadependency. - Keep workspace config (
package.jsonworkspaces orpnpm-workspace.yaml). - Create
turbo.jsonwith task definitions matching Lerna scripts. - Replace
lerna run buildwithturbo run build. - Replace
lerna run test --scope=pkgwithturbo run test --filter=pkg.
From Nx
- Remove
nx.json,project.jsonfiles, andnxdependencies. - Move task config from
project.jsontargets intoturbo.jsontasks. - Replace
nx run-many -t buildwithturbo run build. - Replace
nx affected -t testwithturbo run test --filter=...[origin/main...HEAD].
Differences: Nx uses per-project project.json and its own dependency analysis; Turbo uses a single root turbo.json and relies on the package manager's workspace graph. Nx has generators/executors; Turbo delegates to workspace package.json scripts.
Troubleshooting
turbo run build --dry-run # show what would run
turbo run build --graph # output task graph (DOT format)
turbo run build --summarize # generate run summary JSON
turbo ls # list workspaces
turbo ls --filter=./packages/* # list filtered workspaces
TURBO_LOG_VERBOSITY=debug turbo run build # debug cache misses
Version History
- e0220ca Current 2026-07-05 20:45


