All Agent Skills

Otherwshobson-agents

turborepo-caching

Configure Turborepo for efficient monorepo builds with local and remote caching. Use when setting up Turborepo, optimizing build pipelines, or implementing distributed caching.

3.9k est. installs39.1k stars

Estimated installs are a discovery signal based on public repository popularity and source completeness, not recorded Dokki installation events.

Skill provenance

Repository

wshobson/agents

Pinned commit

d82998e7df39

License

MIT

Execution

Instructions only

Complete source instructions

SKILL.md

Turborepo Caching

Production patterns for Turborepo build optimization.

When to Use This Skill

  • Setting up new Turborepo projects
  • Configuring build pipelines
  • Implementing remote caching
  • Optimizing CI/CD performance
  • Migrating from other monorepo tools
  • Debugging cache misses

Core Concepts

1. Turborepo Architecture

Workspace Root/├── apps/│   ├── web/│   │   └── package.json│   └── docs/│       └── package.json├── packages/│   ├── ui/│   │   └── package.json│   └── config/│       └── package.json├── turbo.json└── package.json

2. Pipeline Concepts

ConceptDescription
dependsOnTasks that must complete first
cacheWhether to cache outputs
outputsFiles to cache
inputsFiles that affect cache key
persistentLong-running tasks (dev servers)

Templates

Template 1: turbo.json Configuration

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

Template 2: Package-Specific Pipeline

json
// apps/web/turbo.json{  "$schema": "https://turbo.build/schema.json",  "extends": ["//"],  "pipeline": {    "build": {      "outputs": [".next/**", "!.next/cache/**"],      "env": ["NEXT_PUBLIC_API_URL", "NEXT_PUBLIC_ANALYTICS_ID"]    },    "test": {      "outputs": ["coverage/**"],      "inputs": ["src/**", "tests/**", "jest.config.js"]    }  }}

Template 3: Remote Caching with Vercel

bash
# Login to Vercelnpx turbo login
# Link to Vercel projectnpx turbo link
# Run with remote cacheturbo build --remote-only
# CI environment variablesTURBO_TOKEN=your-tokenTURBO_TEAM=your-team
yaml
# .github/workflows/ci.ymlname: CI
on:  push:    branches: [main]  pull_request:
env:  TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}  TURBO_TEAM: ${{ vars.TURBO_TEAM }}
jobs:  build:    runs-on: ubuntu-latest    steps:      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4        with:          node-version: 20          cache: "npm"
      - name: Install dependencies        run: npm ci
      - name: Build        run: npx turbo build --filter='...[origin/main]'
      - name: Test        run: npx turbo test --filter='...[origin/main]'

Template 4: Self-Hosted Remote Cache

typescript
// Custom remote cache server (Express)import express from "express";import { createReadStream, createWriteStream } from "fs";import { mkdir } from "fs/promises";import { join } from "path";
const app = express();const CACHE_DIR = "./cache";
// Get artifactapp.get("/v8/artifacts/:hash", async (req, res) => {  const { hash } = req.params;  const team = req.query.teamId || "default";  const filePath = join(CACHE_DIR, team, hash);
  try {    const stream = createReadStream(filePath);    stream.pipe(res);  } catch {    res.status(404).send("Not found");  }});
// Put artifactapp.put("/v8/artifacts/:hash", async (req, res) => {  const { hash } = req.params;  const team = req.query.teamId || "default";  const dir = join(CACHE_DIR, team);  const filePath = join(dir, hash);
  await mkdir(dir, { recursive: true });
  const stream = createWriteStream(filePath);  req.pipe(stream);
  stream.on("finish", () => {    res.json({      urls: [`${req.protocol}://${req.get("host")}/v8/artifacts/${hash}`],    });  });});
// Check artifact existsapp.head("/v8/artifacts/:hash", async (req, res) => {  const { hash } = req.params;  const team = req.query.teamId || "default";  const filePath = join(CACHE_DIR, team, hash);
  try {    await fs.access(filePath);    res.status(200).end();  } catch {    res.status(404).end();  }});
app.listen(3000);
json
// turbo.json for self-hosted cache{  "remoteCache": {    "signature": false  }}
bash
# Use self-hosted cacheturbo build --api="http://localhost:3000" --token="my-token" --team="my-team"

Template 5: Filtering and Scoping

bash
# Build specific packageturbo build --filter=@myorg/web
# Build package and its dependenciesturbo build --filter=@myorg/web...
# Build package and its dependentsturbo build --filter=...@myorg/ui
# Build changed packages since mainturbo build --filter='...[origin/main]'
# Build packages in directoryturbo build --filter='./apps/*'
# Combine filtersturbo build --filter=@myorg/web --filter=@myorg/docs
# Exclude packageturbo build --filter='!@myorg/docs'
# Include dependencies of changedturbo build --filter='...[HEAD^1]...'

Template 6: Advanced Pipeline Configuration

json
{  "$schema": "https://turbo.build/schema.json",  "pipeline": {    "build": {      "dependsOn": ["^build"],      "outputs": ["dist/**"],      "inputs": ["$TURBO_DEFAULT$", "!**/*.md", "!**/*.test.*"]    },    "test": {      "dependsOn": ["^build"],      "outputs": ["coverage/**"],      "inputs": ["src/**", "tests/**", "*.config.*"],      "env": ["CI", "NODE_ENV"]    },    "test:e2e": {      "dependsOn": ["build"],      "outputs": [],      "cache": false    },    "deploy": {      "dependsOn": ["build", "test", "lint"],      "outputs": [],      "cache": false    },    "db:generate": {      "cache": false    },    "db:push": {      "cache": false,      "dependsOn": ["db:generate"]    },    "@myorg/web#build": {      "dependsOn": ["^build", "@myorg/db#db:generate"],      "outputs": [".next/**"],      "env": ["NEXT_PUBLIC_*"]    }  }}

Template 7: Root package.json Setup

json
{  "name": "my-turborepo",  "private": true,  "workspaces": ["apps/*", "packages/*"],  "scripts": {    "build": "turbo build",    "dev": "turbo dev",    "lint": "turbo lint",    "test": "turbo test",    "clean": "turbo clean && rm -rf node_modules",    "format": "prettier --write \"**/*.{ts,tsx,md}\"",    "changeset": "changeset",    "version-packages": "changeset version",    "release": "turbo build --filter=./packages/* && changeset publish"  },  "devDependencies": {    "turbo": "^1.10.0",    "prettier": "^3.0.0",    "@changesets/cli": "^2.26.0"  },  "packageManager": "npm@10.0.0"}

Debugging Cache

bash
# Dry run to see what would runturbo build --dry-run
# Verbose output with hashesturbo build --verbosity=2
# Show task graphturbo build --graph
# Force no cacheturbo build --force
# Show cache statusturbo build --summarize
# Debug specific taskTURBO_LOG_VERBOSITY=debug turbo build --filter=@myorg/web

Best Practices

Do's

  • Define explicit inputs - Avoid cache invalidation
  • Use workspace protocol - "@myorg/ui": "workspace:*"
  • Enable remote caching - Share across CI and local
  • Filter in CI - Build only affected packages
  • Cache build outputs - Not source files

Don'ts

  • Don't cache dev servers - Use persistent: true
  • Don't include secrets in env - Use runtime env vars
  • Don't ignore dependsOn - Causes race conditions
  • Don't over-filter - May miss dependencies

Same repository

Start your company of agents
today.

Free to start. Your first team is one sentence away.