JavaScript 6 min read

Turborepo: High-Performance Monorepo Build System

Master Turborepo for monorepo management. Learn workspace setup, caching, pipelines, and build performant multi-package JavaScript projects.

MR

Moshiour Rahman

Advertisement

What is Turborepo?

Turborepo is a high-performance build system for JavaScript and TypeScript monorepos. It provides intelligent caching, parallel execution, and incremental builds to dramatically speed up development.

Key Features

FeatureDescription
CachingLocal and remote build caching
ParallelizationRun tasks concurrently
IncrementalOnly rebuild what changed
PipelinesDefine task dependencies

Getting Started

Create New Monorepo

# Create new Turborepo
npx create-turbo@latest my-monorepo

# Or with specific package manager
npx create-turbo@latest my-monorepo --package-manager pnpm

Add to Existing Project

# Install Turborepo
npm install turbo --save-dev

# Or globally
npm install turbo --global

Project Structure

my-monorepo/
├── apps/
│   ├── web/
│   │   ├── package.json
│   │   └── ...
│   └── docs/
│       ├── package.json
│       └── ...
├── packages/
│   ├── ui/
│   │   ├── package.json
│   │   └── ...
│   ├── config/
│   │   ├── eslint/
│   │   └── typescript/
│   └── utils/
│       ├── package.json
│       └── ...
├── package.json
├── turbo.json
└── pnpm-workspace.yaml

Configuration

turbo.json

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

Workspace Configuration

# pnpm-workspace.yaml
packages:
  - 'apps/*'
  - 'packages/*'
// package.json (npm/yarn workspaces)
{
  "workspaces": [
    "apps/*",
    "packages/*"
  ]
}

Root package.json

{
  "name": "my-monorepo",
  "private": true,
  "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"
  },
  "devDependencies": {
    "turbo": "^1.10.0"
  },
  "packageManager": "pnpm@8.0.0"
}

Pipeline Configuration

Task Dependencies

{
  "pipeline": {
    // ^build means run build in dependencies first
    "build": {
      "dependsOn": ["^build"],
      "outputs": ["dist/**"]
    },

    // Run lint after linting dependencies
    "lint": {
      "dependsOn": ["^lint"]
    },

    // Run test after build completes
    "test": {
      "dependsOn": ["build"]
    },

    // Deploy depends on build and test
    "deploy": {
      "dependsOn": ["build", "test", "lint"],
      "outputs": []
    }
  }
}

Caching

{
  "pipeline": {
    "build": {
      "dependsOn": ["^build"],
      // Files that are outputs
      "outputs": ["dist/**", ".next/**"],
      // Files that affect cache
      "inputs": [
        "src/**",
        "!src/**/*.test.ts"
      ]
    },
    "dev": {
      // Never cache dev server
      "cache": false,
      // Keep running
      "persistent": true
    }
  }
}

Environment Variables

{
  "globalEnv": ["CI", "NODE_ENV"],
  "pipeline": {
    "build": {
      "dependsOn": ["^build"],
      "env": ["DATABASE_URL", "API_KEY"],
      "outputs": ["dist/**"]
    },
    "test": {
      "env": ["TEST_DATABASE_URL"],
      "outputs": ["coverage/**"]
    }
  }
}

Running Tasks

Basic Commands

# Run build in all workspaces
turbo run build

# Run multiple tasks
turbo run build lint test

# Run in specific workspace
turbo run build --filter=web

# Run in workspace and dependencies
turbo run build --filter=web...

# Run in dependents only
turbo run build --filter=...ui

# Run with pattern matching
turbo run build --filter="@myorg/*"
turbo run build --filter="./apps/*"

Filtering

# By package name
turbo run build --filter=@myorg/web

# By directory
turbo run build --filter=./apps/web

# Include dependencies
turbo run build --filter=web...

# Include dependents
turbo run build --filter=...ui

# Changed packages (git)
turbo run build --filter=[HEAD^1]

# Combining filters
turbo run build --filter=...@myorg/ui --filter=@myorg/web

Parallel Execution

# Limit concurrency
turbo run build --concurrency=4
turbo run build --concurrency=50%

# Sequential execution
turbo run build --concurrency=1

# Continue on error
turbo run test --continue

Shared Packages

UI Package

// packages/ui/package.json
{
  "name": "@myorg/ui",
  "version": "0.0.1",
  "main": "./dist/index.js",
  "types": "./dist/index.d.ts",
  "exports": {
    ".": {
      "import": "./dist/index.mjs",
      "require": "./dist/index.js"
    },
    "./button": {
      "import": "./dist/button.mjs",
      "require": "./dist/button.js"
    }
  },
  "scripts": {
    "build": "tsup src/index.tsx --format cjs,esm --dts",
    "dev": "tsup src/index.tsx --format cjs,esm --dts --watch",
    "lint": "eslint src/"
  },
  "peerDependencies": {
    "react": "^18.0.0"
  }
}
// packages/ui/src/index.tsx
export * from './button';
export * from './card';
export * from './input';

Consuming Shared Packages

// apps/web/package.json
{
  "name": "@myorg/web",
  "dependencies": {
    "@myorg/ui": "workspace:*",
    "@myorg/utils": "workspace:*"
  }
}
// apps/web/src/app.tsx
import { Button, Card } from '@myorg/ui';
import { formatDate } from '@myorg/utils';

export function App() {
  return (
    <Card>
      <p>Today is {formatDate(new Date())}</p>
      <Button>Click me</Button>
    </Card>
  );
}

Shared Configuration

TypeScript Config

// packages/config/typescript/base.json
{
  "$schema": "https://json.schemastore.org/tsconfig",
  "compilerOptions": {
    "target": "ES2020",
    "module": "ESNext",
    "moduleResolution": "bundler",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "declaration": true,
    "declarationMap": true,
    "sourceMap": true
  }
}
// packages/config/typescript/react.json
{
  "extends": "./base.json",
  "compilerOptions": {
    "jsx": "react-jsx",
    "lib": ["DOM", "DOM.Iterable", "ES2020"]
  }
}
// apps/web/tsconfig.json
{
  "extends": "@myorg/config/typescript/react.json",
  "include": ["src"],
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@/*": ["./src/*"]
    }
  }
}

ESLint Config

// packages/config/eslint/react.js
module.exports = {
  extends: [
    'eslint:recommended',
    'plugin:@typescript-eslint/recommended',
    'plugin:react/recommended',
    'plugin:react-hooks/recommended',
    'prettier'
  ],
  parser: '@typescript-eslint/parser',
  plugins: ['@typescript-eslint', 'react'],
  settings: {
    react: {
      version: 'detect'
    }
  },
  rules: {
    'react/react-in-jsx-scope': 'off'
  }
};
// apps/web/.eslintrc.js
module.exports = {
  root: true,
  extends: ['@myorg/config/eslint/react']
};

Remote Caching

Vercel Remote Cache

# Login to Vercel
turbo login

# Link to Vercel project
turbo link

# Run with remote cache
turbo run build

Self-Hosted Cache

// turbo.json
{
  "remoteCache": {
    "signature": true
  }
}
# Set remote cache URL
export TURBO_API="https://cache.example.com"
export TURBO_TOKEN="your-token"
export TURBO_TEAM="your-team"

turbo run build

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
        with:
          fetch-depth: 2

      - uses: pnpm/action-setup@v2
        with:
          version: 8

      - uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: 'pnpm'

      - run: pnpm install

      - run: pnpm turbo run build lint test
        env:
          TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
          TURBO_TEAM: ${{ vars.TURBO_TEAM }}

Affected Packages Only

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - run: pnpm install

      # Only build changed packages
      - run: pnpm turbo run build --filter=[HEAD^1]

Generator

Create Package Generator

# Install generator
turbo gen
// turbo/generators/config.ts
import type { PlopTypes } from '@turbo/gen';

export default function generator(plop: PlopTypes.NodePlopAPI) {
  plop.setGenerator('package', {
    description: 'Create a new package',
    prompts: [
      {
        type: 'input',
        name: 'name',
        message: 'Package name'
      }
    ],
    actions: [
      {
        type: 'add',
        path: 'packages/{{name}}/package.json',
        templateFile: 'templates/package.json.hbs'
      },
      {
        type: 'add',
        path: 'packages/{{name}}/src/index.ts',
        template: 'export const {{name}} = () => {};'
      }
    ]
  });
}

Summary

FeatureCommand
Build allturbo run build
Filter--filter=package-name
Parallel--concurrency=N
Remote cacheturbo login && turbo link
Generateturbo gen

Turborepo provides fast, scalable monorepo tooling for JavaScript and TypeScript projects.

Advertisement

MR

Moshiour Rahman

Software Architect & AI Engineer

Share:
MR

Moshiour Rahman

Software Architect & AI Engineer

Enterprise software architect with deep expertise in financial systems, distributed architecture, and AI-powered applications. Building large-scale systems at Fortune 500 companies. Specializing in LLM orchestration, multi-agent systems, and cloud-native solutions. I share battle-tested patterns from real enterprise projects.

Related Articles

Comments

Comments are powered by GitHub Discussions.

Configure Giscus at giscus.app to enable comments.