Turborepo for Node
Turborepo orchestrates workspace tasks with remote caching so unchanged packages skip rebuilds in CI and locally.
Search across all documentation pages
Turborepo orchestrates workspace tasks with remote caching so unchanged packages skip rebuilds in CI and locally.
Quick-reference recipe card - copy-paste ready.
// turbo.json
{
"$schema": "https://turbo.build/schema.json",
"tasks": {
"build": {
"dependsOn": ["^build"],
"outputs": ["dist/**"]
},
"test": {
"dependsOn": ["build"],
"outputs": []
},
"typecheck": {
"dependsOn": ["^build"],
"outputs": []
}
}
}npx turbo run build test typecheckWhen to reach for this:
build/test in CI.platform/
turbo.json
package.json # workspaces
apps/
api/package.json
packages/
shared/package.json
// package.json (root)
{
"private": true,
"workspaces": ["apps/*", "packages/*"],
"scripts": {
"build": "turbo run build",
"test": "turbo run test",
"dev": "turbo run dev --parallel"
},
"devDependencies": {
"turbo": "^2.3.0",
"typescript": "^5.6.0"
}
}// packages/shared/package.json
{
"name": "@acme/shared",
"scripts": {
"build": "tsc -p tsconfig.json",
"test": "node --import tsx --test"
}
}// apps/api/package.json
{
"name": "@acme/api",
"dependencies": { "@acme/shared": "workspace:*", "fastify": "^5.0.0" },
"scripts": {
"build": "tsc -p tsconfig.json",
"dev": "tsx watch src/server.ts",
"test": "node --import tsx --test"
}
}npm install
npx turbo run build --filter=@acme/api...What this demonstrates:
^build runs dependency package builds before dependents.--filter=@acme/api... includes the API and its workspace dependencies.outputs tells Turbo what to cache between runs.outputs from cache on cache hit.dependsOn builds a DAG; test waits for build artifacts.dev tasks are typically persistent: true and not cached.| Field | Purpose |
|---|---|
dependsOn | Upstream task ordering (^build = deps first) |
outputs | Folders restored from cache (dist/**) |
inputs | Fine-tune hash (default: package files) |
env | Env vars that bust cache when changed |
{
"tasks": {
"build": { "dependsOn": ["^build"], "outputs": ["dist/**"] },
"typecheck": { "dependsOn": ["^build"] }
}
}typecheck from build if you want faster CI jobs that skip emit when only checking types.tsconfig emits to dist/ consistently for cache paths.outputs - Turbo caches nothing useful; every build reruns fully. Fix: declare dist/** per compile task.@acme/api alone skips dependency builds. Fix: use @acme/api... (three dots) for dependents chain.inputs.env lists bust cache when tokens change. Fix: only list env vars that affect build output."persistent": true and no outputs on dev.| Alternative | Use When | Don't Use When |
|---|---|---|
npm run -w scripts only | 2-package monorepo | CI time grows linearly with packages |
| Nx | Generators, affected graph, enforcement | Team wants minimal config |
| Bazel | Huge polyglot repos | Node-only backend shop |
No. Turbo runs on top of workspaces. You still use npm ci and workspace:* linking.
npx turbo run dev --filter=@acme/apiAdd --parallel when running multiple dev servers.
Compiled dist/**, generated OpenAPI specs, or *.tsbuildinfo if you cache incremental builds.
turbo login and TURBO_TOKEN in CI. Self-host with S3-compatible storage for air-gapped teams.
Yes in separate apps/* workspaces. Shared code lives in packages/ without framework imports.
Yes when tests import dist/ or compiled types. Pure tsx source tests may omit build dependency if configured carefully.
Changing root package-lock.json or turbo.json invalidates hashes globally for affected tasks.
No. Add when a second package or service appears and CI exceeds ~5 minutes routinely.
Run turbo prune --scope=@acme/api --docker to generate a minimal subset for multi-stage images.
Nest has its own monorepo mode; many teams still add Turbo for cross-framework packages/ libs.
Stack versions: This page was written for Node.js 24.18.0 (Active LTS), npm 10+, TypeScript 5.6+, Express 5, Fastify 5, and NestJS 11.
Reviewed by Chris St. John·Last updated Jul 19, 2026