Skip to main content
Technology & EngineeringMonorepo175 lines

Turborepo

Build system orchestration with Turborepo for high-performance monorepo task running and caching

Quick Summary28 lines
You are an expert in Turborepo for managing monorepo build systems, task orchestration, and remote caching.

## Key Points

- `"dependsOn": ["^build"]` — Run `build` in all dependency packages first (topological).
- `"dependsOn": ["build"]` — Run `build` in the same package first.
- `"dependsOn": ["^build", "type-check"]` — Combine both topological and same-package deps.
1. **Define all outputs explicitly** — Turborepo caches based on outputs; missing outputs means broken cache restores.
2. **Use `inputs` to narrow cache keys** — Specify only relevant source files so unrelated changes don't bust the cache.
3. **Never cache `dev`** — Set `"cache": false` and `"persistent": true` for long-running dev servers.
4. **Declare environment variables** — Use `env` and `globalEnv` so environment changes correctly invalidate caches.
5. **Use `--filter` in CI** — Only build and test affected packages to cut CI time dramatically.
6. **Enable Remote Caching** — Share cache across CI runs and team members to avoid redundant work.
7. **Use `--dry-run`** — Debug task graphs with `turbo run build --dry-run` to verify what will execute.
- **Missing `^` in dependsOn** — `"dependsOn": ["build"]` runs build in the *same* package; `"dependsOn": ["^build"]` runs it in *dependencies*. Confusing these breaks the build order.
- **Not listing all outputs** — If a build produces files outside `dist/`, cache restores will be incomplete and builds will appear to succeed but have missing artifacts.

## Quick Example

```bash
# Create a new Turborepo
npx create-turbo@latest

# Add to an existing monorepo
npm install turbo --save-dev
```
skilldb get monorepo-skills/TurborepoFull skill: 175 lines
Paste into your CLAUDE.md or agent config

Turborepo — Monorepo Management

You are an expert in Turborepo for managing monorepo build systems, task orchestration, and remote caching.

Core Philosophy

Overview

Turborepo is a high-performance build system for JavaScript and TypeScript monorepos. It provides intelligent task scheduling, local and remote caching, and incremental builds. Turborepo understands your dependency graph and runs tasks in the optimal order with maximum parallelism.

Setup & Configuration

Installation

# Create a new Turborepo
npx create-turbo@latest

# Add to an existing monorepo
npm install turbo --save-dev

turbo.json Configuration

{
  "$schema": "https://turbo.build/schema.json",
  "globalDependencies": ["**/.env.*local"],
  "globalEnv": ["NODE_ENV"],
  "pipeline": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": ["dist/**", ".next/**", "!.next/cache/**"],
      "env": ["NEXT_PUBLIC_API_URL"]
    },
    "test": {
      "dependsOn": ["build"],
      "inputs": ["src/**/*.tsx", "src/**/*.ts", "test/**/*.ts"],
      "outputs": ["coverage/**"]
    },
    "lint": {
      "outputs": []
    },
    "dev": {
      "cache": false,
      "persistent": true
    },
    "type-check": {
      "dependsOn": ["^build"],
      "outputs": []
    }
  }
}

Package-Level Configuration

In each package's package.json:

{
  "name": "@myorg/web",
  "scripts": {
    "build": "next build",
    "dev": "next dev",
    "lint": "eslint .",
    "test": "vitest run"
  }
}

Core Patterns

Task Dependencies

  • "dependsOn": ["^build"] — Run build in all dependency packages first (topological).
  • "dependsOn": ["build"] — Run build in the same package first.
  • "dependsOn": ["^build", "type-check"] — Combine both topological and same-package deps.

Filtering

# Run build only in @myorg/web and its dependencies
turbo run build --filter=@myorg/web...

# Run tests in all packages that changed since main
turbo run test --filter=...[main]

# Run lint in packages under apps/
turbo run lint --filter=./apps/*

# Exclude a package
turbo run build --filter=!@myorg/docs

Remote Caching

# Login to Vercel Remote Cache
turbo login

# Link your repo
turbo link

# Or self-host with environment variables
TURBO_TOKEN=your-token
TURBO_TEAM=your-team
TURBO_API=https://your-cache-server.com

Environment Variable Handling

{
  "pipeline": {
    "build": {
      "env": ["DATABASE_URL", "API_SECRET"],
      "passThroughEnv": ["CI", "GITHUB_TOKEN"]
    }
  }
}

Outputs Configuration

{
  "pipeline": {
    "build": {
      "outputs": ["dist/**", "build/**", ".next/**", "!.next/cache/**"]
    },
    "test": {
      "outputs": ["coverage/**"]
    },
    "lint": {
      "outputs": []
    }
  }
}

Best Practices

  1. Define all outputs explicitly — Turborepo caches based on outputs; missing outputs means broken cache restores.
  2. Use inputs to narrow cache keys — Specify only relevant source files so unrelated changes don't bust the cache.
  3. Never cache dev — Set "cache": false and "persistent": true for long-running dev servers.
  4. Declare environment variables — Use env and globalEnv so environment changes correctly invalidate caches.
  5. Use --filter in CI — Only build and test affected packages to cut CI time dramatically.
  6. Enable Remote Caching — Share cache across CI runs and team members to avoid redundant work.
  7. Use --dry-run — Debug task graphs with turbo run build --dry-run to verify what will execute.

Common Pitfalls

  • Missing ^ in dependsOn"dependsOn": ["build"] runs build in the same package; "dependsOn": ["^build"] runs it in dependencies. Confusing these breaks the build order.
  • Not listing all outputs — If a build produces files outside dist/, cache restores will be incomplete and builds will appear to succeed but have missing artifacts.
  • Forgetting environment variables in config — Turborepo won't know to invalidate the cache when an env var changes unless it's declared in env or globalEnv.
  • Caching non-deterministic tasks — Tasks that depend on timestamps or random values will produce stale results from cache.
  • Using turbo run for scripts that modify the workspace — Tasks like codegen that write to node_modules or change source files can corrupt cache state if not handled carefully.

Anti-Patterns

Over-engineering for hypothetical scale. Building for millions of users when you have hundreds adds complexity without value. Solve today's problems first.

Ignoring the existing ecosystem. Reinventing functionality that mature libraries already provide well wastes time and introduces unnecessary risk.

Premature abstraction. Creating elaborate frameworks and utilities before you have enough concrete cases to know what the abstraction should look like produces the wrong abstraction.

Neglecting error handling at boundaries. Internal code can trust its inputs, but system boundaries (user input, APIs, file I/O) require defensive validation.

Skipping documentation for obvious code. What is obvious to you today will not be obvious to your colleague next month or to you next year.

Install this skill directly: skilldb add monorepo-skills

Get CLI access →