Turborepo Caching
Unverified●24/40Claude Code◐PartialHas SKILL.md but declares no allowed-tools — Claude Code will ask for permission each time
Cursor·UnknownWe have not crawled the repo tree, so we will not guess
Codex·UnknownWe have not crawled the repo tree, so we will not guess
Gemini CLI·UnknownThe spec defines no detection rule for Gemini
Copilot·UnknownWe have not crawled the repo tree, so we will not guess
npx agentalley add turborepo-cachingWho is stuck, and on what
Configure Turborepo for efficient monorepo builds with local and remote caching. Use when setting up Turborepo, optimizing build pipelines, or implementing distributed caching.
The whole source
Frontmatter — 2 properties
| name | turborepo-caching |
|---|---|
| description | Configure Turborepo for efficient monorepo builds with local and remote caching. Use when setting up Turborepo, optimizing build pipelines, or implementing distributed caching. |
| 1 | --- |
| 2 | name: turborepo-caching |
| 3 | description: Configure Turborepo for efficient monorepo builds with local and remote caching. Use when setting up Turborepo, optimizing build pipelines, or implementing distributed caching. |
| 4 | ---A5 — No allowed-tools declared — no way to tell what this skill may touch |
| 5 | |
| 6 | # Turborepo Caching |
| 7 | |
| 8 | Production patterns for Turborepo build optimization. |
| 9 | |
| 10 | ## When to Use This Skill |
| 11 | |
| 12 | - Setting up new Turborepo projects |
| 13 | - Configuring build pipelines |
| 14 | - Implementing remote caching |
| 15 | - Optimizing CI/CD performance |
| 16 | - Migrating from other monorepo tools |
| 17 | - Debugging cache misses |
| 18 | |
| 19 | ## Core Concepts |
| 20 | |
| 21 | ### 1. Turborepo Architecture |
| 22 | |
| 23 | ``` |
| 24 | Workspace Root/ |
| 25 | ├── apps/ |
| 26 | │ ├── web/ |
| 27 | │ │ └── package.json |
| 28 | │ └── docs/ |
| 29 | │ └── package.json |
| 30 | ├── packages/ |
| 31 | │ ├── ui/ |
| 32 | │ │ └── package.json |
| 33 | │ └── config/ |
| 34 | │ └── package.json |
| 35 | ├── turbo.json |
| 36 | └── package.json |
| 37 | ``` |
| 38 | |
| 39 | ### 2. Pipeline Concepts |
| 40 | |
| 41 | | Concept | Description | |
| 42 | | -------------- | -------------------------------- | |
| 43 | | **dependsOn** | Tasks that must complete first | |
| 44 | | **cache** | Whether to cache outputs | |
| 45 | | **outputs** | Files to cache | |
| 46 | | **inputs** | Files that affect cache key | |
| 47 | | **persistent** | Long-running tasks (dev servers) | |
| 48 | |
| 49 | ## Templates |
| 50 | |
| 51 | ### Template 1: turbo.json Configuration |
| 52 | |
| 53 | ```json |
| 54 | { |
| 55 | "$schema": "https://turbo.build/schema.json",A2 — Sends to turbo.build — outside the allowlist, and this file also reads environment variables or keys |
| 56 | "globalDependencies": [".env", ".env.local"], |
| 57 | "globalEnv": ["NODE_ENV", "VERCEL_URL"], |
| 58 | "pipeline": { |
| 59 | "build": { |
| 60 | "dependsOn": ["^build"], |
| 61 | "outputs": ["dist/**", ".next/**", "!.next/cache/**"], |
| 62 | "env": ["API_URL", "NEXT_PUBLIC_*"] |
| 63 | }, |
| 64 | "test": { |
| 65 | "dependsOn": ["build"], |
| 66 | "outputs": ["coverage/**"], |
| 67 | "inputs": ["src/**/*.tsx", "src/**/*.ts", "test/**/*.ts"] |
| 68 | }, |
| 69 | "lint": { |
| 70 | "outputs": [], |
| 71 | "cache": true |
| 72 | }, |
| 73 | "typecheck": { |
| 74 | "dependsOn": ["^build"], |
| 75 | "outputs": [] |
| 76 | }, |
| 77 | "dev": { |
| 78 | "cache": false, |
| 79 | "persistent": true |
| 80 | }, |
| 81 | "clean": { |
| 82 | "cache": false |
| 83 | } |
| 84 | } |
| 85 | } |
| 86 | ``` |
| 87 | |
| 88 | ### Template 2: Package-Specific Pipeline |
| 89 | |
| 90 | ```json |
| 91 | // apps/web/turbo.json |
| 92 | { |
| 93 | "$schema": "https://turbo.build/schema.json", |
| 94 | "extends": ["//"], |
| 95 | "pipeline": { |
| 96 | "build": { |
| 97 | "outputs": [".next/**", "!.next/cache/**"], |
| 98 | "env": ["NEXT_PUBLIC_API_URL", "NEXT_PUBLIC_ANALYTICS_ID"] |
| 99 | }, |
| 100 | "test": { |
| 101 | "outputs": ["coverage/**"], |
| 102 | "inputs": ["src/**", "tests/**", "jest.config.js"] |
| 103 | } |
| 104 | } |
| 105 | } |
| 106 | ``` |
| 107 | |
| 108 | ### Template 3: Remote Caching with Vercel |
| 109 | |
| 110 | ```bash |
| 111 | # Login to Vercel |
| 112 | npx turbo login |
| 113 | |
| 114 | # Link to Vercel project |
| 115 | npx turbo link |
| 116 | |
| 117 | # Run with remote cache |
| 118 | turbo build --remote-only |
| 119 | |
| 120 | # CI environment variables |
| 121 | TURBO_TOKEN=your-token |
| 122 | TURBO_TEAM=your-team |
| 123 | ``` |
| 124 | |
| 125 | ```yaml |
| 126 | # .github/workflows/ci.yml |
| 127 | name: CI |
| 128 | |
| 129 | on: |
| 130 | push: |
| 131 | branches: [main] |
| 132 | pull_request: |
| 133 | |
| 134 | env: |
| 135 | TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }} |
| 136 | TURBO_TEAM: ${{ vars.TURBO_TEAM }} |
| 137 | |
| 138 | jobs: |
| 139 | build: |
| 140 | runs-on: ubuntu-latest |
| 141 | steps: |
| 142 | - uses: actions/checkout@v4 |
| 143 | |
| 144 | - uses: actions/setup-node@v4 |
| 145 | with: |
| 146 | node-version: 20 |
| 147 | cache: "npm" |
| 148 | |
| 149 | - name: Install dependencies |
| 150 | run: npm ci |
| 151 | |
| 152 | - name: Build |
| 153 | run: npx turbo build --filter='...[origin/main]' |
| 154 | |
| 155 | - name: Test |
| 156 | run: npx turbo test --filter='...[origin/main]' |
| 157 | ``` |
| 158 | |
| 159 | ### Template 4: Self-Hosted Remote Cache |
| 160 | |
| 161 | ```typescript |
| 162 | // Custom remote cache server (Express) |
| 163 | import express from "express"; |
| 164 | import { createReadStream, createWriteStream } from "fs"; |
| 165 | import { mkdir } from "fs/promises"; |
| 166 | import { join } from "path"; |
| 167 | |
| 168 | const app = express(); |
| 169 | const CACHE_DIR = "./cache"; |
| 170 | |
| 171 | // Get artifact |
| 172 | app.get("/v8/artifacts/:hash", async (req, res) => { |
| 173 | const { hash } = req.params; |
| 174 | const team = req.query.teamId || "default"; |
| 175 | const filePath = join(CACHE_DIR, team, hash); |
| 176 | |
| 177 | try { |
| 178 | const stream = createReadStream(filePath); |
| 179 | stream.pipe(res); |
| 180 | } catch { |
| 181 | res.status(404).send("Not found"); |
| 182 | } |
| 183 | }); |
| 184 | |
| 185 | // Put artifact |
| 186 | app.put("/v8/artifacts/:hash", async (req, res) => { |
| 187 | const { hash } = req.params; |
| 188 | const team = req.query.teamId || "default"; |
| 189 | const dir = join(CACHE_DIR, team); |
| 190 | const filePath = join(dir, hash); |
| 191 | |
| 192 | await mkdir(dir, { recursive: true }); |
| 193 | |
| 194 | const stream = createWriteStream(filePath); |
| 195 | req.pipe(stream); |
| 196 | |
| 197 | stream.on("finish", () => { |
| 198 | res.json({ |
| 199 | urls: [`${req.protocol}://${req.get("host")}/v8/artifacts/${hash}`], |
| 200 | }); |
| 201 | }); |
| 202 | }); |
| 203 | |
| 204 | // Check artifact exists |
| 205 | app.head("/v8/artifacts/:hash", async (req, res) => { |
| 206 | const { hash } = req.params; |
| 207 | const team = req.query.teamId || "default"; |
| 208 | const filePath = join(CACHE_DIR, team, hash); |
| 209 | |
| 210 | try { |
| 211 | await fs.access(filePath); |
| 212 | res.status(200).end(); |
| 213 | } catch { |
| 214 | res.status(404).end(); |
| 215 | } |
| 216 | }); |
| 217 | |
| 218 | app.listen(3000); |
| 219 | ``` |
| 220 | |
| 221 | ```json |
| 222 | // turbo.json for self-hosted cache |
| 223 | { |
| 224 | "remoteCache": { |
| 225 | "signature": false |
| 226 | } |
| 227 | } |
| 228 | ``` |
| 229 | |
| 230 | ```bash |
| 231 | # Use self-hosted cache |
| 232 | turbo build --api="http://localhost:3000" --token="my-token" --team="my-team" |
| 233 | ``` |
| 234 | |
| 235 | ### Template 5: Filtering and Scoping |
| 236 | |
| 237 | ```bash |
| 238 | # Build specific package |
| 239 | turbo build --filter=@myorg/web |
| 240 | |
| 241 | # Build package and its dependencies |
| 242 | turbo build --filter=@myorg/web... |
| 243 | |
| 244 | # Build package and its dependents |
| 245 | turbo build --filter=...@myorg/ui |
| 246 | |
| 247 | # Build changed packages since main |
| 248 | turbo build --filter='...[origin/main]' |
| 249 | |
| 250 | # Build packages in directory |
| 251 | turbo build --filter='./apps/*' |
| 252 | |
| 253 | # Combine filters |
| 254 | turbo build --filter=@myorg/web --filter=@myorg/docs |
| 255 | |
| 256 | # Exclude package |
| 257 | turbo build --filter='!@myorg/docs' |
| 258 | |
| 259 | # Include dependencies of changed |
| 260 | turbo build --filter='...[HEAD^1]...' |
| 261 | ``` |
| 262 | |
| 263 | ### Template 6: Advanced Pipeline Configuration |
| 264 | |
| 265 | ```json |
| 266 | { |
| 267 | "$schema": "https://turbo.build/schema.json", |
| 268 | "pipeline": { |
| 269 | "build": { |
| 270 | "dependsOn": ["^build"], |
| 271 | "outputs": ["dist/**"], |
| 272 | "inputs": ["$TURBO_DEFAULT$", "!**/*.md", "!**/*.test.*"] |
| 273 | }, |
| 274 | "test": { |
| 275 | "dependsOn": ["^build"], |
| 276 | "outputs": ["coverage/**"], |
| 277 | "inputs": ["src/**", "tests/**", "*.config.*"], |
| 278 | "env": ["CI", "NODE_ENV"] |
| 279 | }, |
| 280 | "test:e2e": { |
| 281 | "dependsOn": ["build"], |
| 282 | "outputs": [], |
| 283 | "cache": false |
| 284 | }, |
| 285 | "deploy": { |
| 286 | "dependsOn": ["build", "test", "lint"], |
| 287 | "outputs": [], |
| 288 | "cache": false |
| 289 | }, |
| 290 | "db:generate": { |
| 291 | "cache": false |
| 292 | }, |
| 293 | "db:push": { |
| 294 | "cache": false, |
| 295 | "dependsOn": ["db:generate"] |
| 296 | }, |
| 297 | "@myorg/web#build": { |
| 298 | "dependsOn": ["^build", "@myorg/db#db:generate"], |
| 299 | "outputs": [".next/**"], |
| 300 | "env": ["NEXT_PUBLIC_*"] |
| 301 | } |
| 302 | } |
| 303 | } |
| 304 | ``` |
| 305 | |
| 306 | ### Template 7: Root package.json Setup |
| 307 | |
| 308 | ```json |
| 309 | { |
| 310 | "name": "my-turborepo", |
| 311 | "private": true, |
| 312 | "workspaces": ["apps/*", "packages/*"], |
| 313 | "scripts": { |
| 314 | "build": "turbo build", |
| 315 | "dev": "turbo dev", |
| 316 | "lint": "turbo lint", |
| 317 | "test": "turbo test", |
| 318 | "clean": "turbo clean && rm -rf node_modules", |
| 319 | "format": "prettier --write \"**/*.{ts,tsx,md}\"", |
| 320 | "changeset": "changeset", |
| 321 | "version-packages": "changeset version", |
| 322 | "release": "turbo build --filter=./packages/* && changeset publish" |
| 323 | }, |
| 324 | "devDependencies": { |
| 325 | "turbo": "^1.10.0", |
| 326 | "prettier": "^3.0.0", |
| 327 | "@changesets/cli": "^2.26.0" |
| 328 | }, |
| 329 | "packageManager": "[email protected]" |
| 330 | } |
| 331 | ``` |
| 332 | |
| 333 | ## Debugging Cache |
| 334 | |
| 335 | ```bash |
| 336 | # Dry run to see what would run |
| 337 | turbo build --dry-run |
| 338 | |
| 339 | # Verbose output with hashes |
| 340 | turbo build --verbosity=2 |
| 341 | |
| 342 | # Show task graph |
| 343 | turbo build --graph |
| 344 | |
| 345 | # Force no cache |
| 346 | turbo build --force |
| 347 | |
| 348 | # Show cache status |
| 349 | turbo build --summarize |
| 350 | |
| 351 | # Debug specific task |
| 352 | TURBO_LOG_VERBOSITY=debug turbo build --filter=@myorg/web |
| 353 | ``` |
| 354 | |
| 355 | ## Best Practices |
| 356 | |
| 357 | ### Do's |
| 358 | |
| 359 | - **Define explicit inputs** - Avoid cache invalidation |
| 360 | - **Use workspace protocol** - `"@myorg/ui": "workspace:*"` |
| 361 | - **Enable remote caching** - Share across CI and local |
| 362 | - **Filter in CI** - Build only affected packages |
| 363 | - **Cache build outputs** - Not source files |
| 364 | |
| 365 | ### Don'ts |
| 366 | |
| 367 | - **Don't cache dev servers** - Use `persistent: true` |
| 368 | - **Don't include secrets in env** - Use runtime env vars |
| 369 | - **Don't ignore dependsOn** - Causes race conditions |
| 370 | - **Don't over-filter** - May miss dependencies |
| 371 |
Reviews
Installed this one?Write the first review and take the Trailblazer badge.
Alternatives
Subagent Driven DevelopmentUse when executing implementation plans with independent tasks in the current session◐◐◐◐◐●36/40Python Code Style & DocumentationPython code style, linting, formatting, naming conventions, and documentation standards. Use when writing new code, reviewing style, configuring linters, writing docstrings, or establishing project standards.◐····●35/40Competitor Price Analysis 💲Competitor pricing strategy analysis and market positioning. Price mapping, pricing gaps identification, elasticity signals evaluation, and strategic pricing optimization. Use when the user asks about competitor pricing, price analysis, pricing strategy, or co◐····●34/40Competitor Price Tracker 📊Set up competitor price tracking and monitoring workflows. Track price changes, detect promotions, analyze pricing patterns, and get alerts for competitive price movements.◐····●34/40