Requirements
- Target platform
- OpenClaw
- Install method
- Manual import
- Extraction
- Extract archive
- Prerequisites
- OpenClaw
- Primary doc
- SKILL.md
WHAT: Turborepo monorepo build system - caching, task pipelines, and parallel execution for JS/TS projects. WHEN: User configures turbo.json, creates packages, sets up monorepo, shares code between apps, runs --affected builds, debugs cache misses, or has apps/packages directories. KEYWORDS: turborepo, turbo.json, monorepo, dependsOn, task pipeline, caching, remote cache, --filter, --affected, packages, workspace, pnpm workspace, npm workspace, build optimization
WHAT: Turborepo monorepo build system - caching, task pipelines, and parallel execution for JS/TS projects. WHEN: User configures turbo.json, creates packages, sets up monorepo, shares code between apps, runs --affected builds, debugs cache misses, or has apps/packages directories. KEYWORDS: turborepo, turbo.json, monorepo, dependsOn, task pipeline, caching, remote cache, --filter, --affected, packages, workspace, pnpm workspace, npm workspace, build optimization
Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.
I downloaded a skill package from Yavira. Read SKILL.md from the extracted folder and install it by following the included instructions. Then review README.md for any prerequisites, environment setup, or post-install checks. Tell me what you changed and call out any manual steps you could not complete.
I downloaded an updated skill package from Yavira. Read SKILL.md from the extracted folder, compare it with my current installation, and upgrade it while preserving any custom configuration unless the package docs explicitly say otherwise. Then review README.md for any prerequisites, environment setup, or post-install checks. Summarize what changed and any follow-up checks I should run.
Build system for JavaScript/TypeScript monorepos. Caches task outputs and runs tasks in parallel based on dependency graph.
npx clawhub@latest install turborepo
NEVER create root tasks - Always create package-level tasks in each package's package.json NEVER use turbo <task> shorthand in code - Use turbo run <task> in package.json and CI NEVER bypass turbo - Root scripts must delegate via turbo run, not run tasks directly NEVER chain turbo tasks with && - Let turbo orchestrate dependencies via dependsOn NEVER use --parallel flag - Configure dependsOn correctly instead NEVER put .env at repo root - Use package-level .env files for clarity NEVER use ../ in inputs - Use $TURBO_ROOT$/path for repo root files
DO NOT create Root Tasks. ALWAYS create package tasks. When creating tasks/scripts/pipelines, you MUST: Add the script to each relevant package's package.json Register the task in root turbo.json Root package.json only delegates via turbo run <task> DO NOT put task logic in root package.json. This defeats Turborepo's parallelization. // DO THIS: Scripts in each package // apps/web/package.json { "scripts": { "build": "next build", "lint": "eslint .", "test": "vitest" } } // apps/api/package.json { "scripts": { "build": "tsc", "lint": "eslint .", "test": "vitest" } } // packages/ui/package.json { "scripts": { "build": "tsc", "lint": "eslint .", "test": "vitest" } } // turbo.json - register tasks { "tasks": { "build": { "dependsOn": ["^build"], "outputs": ["dist/**"] }, "lint": {}, "test": { "dependsOn": ["build"] } } } // Root package.json - ONLY delegates, no task logic { "scripts": { "build": "turbo run build", "lint": "turbo run lint", "test": "turbo run test" } } // DO NOT DO THIS - defeats parallelization // Root package.json { "scripts": { "build": "cd apps/web && next build && cd ../api && tsc", "lint": "eslint apps/ packages/", "test": "vitest" } } Root Tasks (//#taskname) are ONLY for tasks that truly cannot exist in packages (rare).
Configure a task? โโ Define task dependencies โ references/configuration/tasks.md โโ Lint/check-types (parallel + caching) โ Use Transit Nodes pattern (see below) โโ Specify build outputs โ references/configuration/tasks.md#outputs โโ Handle environment variables โ references/environment/README.md โโ Set up dev/watch tasks โ references/configuration/tasks.md#persistent โโ Package-specific config โ references/configuration/README.md#package-configurations โโ Global settings (cacheDir, daemon) โ references/configuration/global-options.md
Cache problems? โโ Tasks run but outputs not restored โ Missing `outputs` key โโ Cache misses unexpectedly โ references/caching/gotchas.md โโ Need to debug hash inputs โ Use --summarize or --dry โโ Want to skip cache entirely โ Use --force or cache: false โโ Remote cache not working โ references/caching/remote-cache.md โโ Environment causing misses โ references/environment/gotchas.md
Run only what changed? โโ Changed packages + dependents (RECOMMENDED) โ turbo run build --affected โโ Custom base branch โ --affected --affected-base=origin/develop โโ Manual git comparison โ --filter=...[origin/main] โโ See all filter options โ references/filtering/README.md --affected is the primary way to run only changed packages. It automatically compares against the default branch and includes dependents.
Filter packages? โโ Only changed packages โ --affected (see above) โโ By package name โ --filter=web โโ By directory โ --filter=./apps/* โโ Package + dependencies โ --filter=web... โโ Package + dependents โ --filter=...web โโ Complex combinations โ references/filtering/patterns.md
Environment issues? โโ Vars not available at runtime โ Strict mode filtering (default) โโ Cache hits with wrong env โ Var not in `env` key โโ .env changes not causing rebuilds โ .env not in `inputs` โโ CI variables missing โ references/environment/gotchas.md โโ Framework vars (NEXT_PUBLIC_*) โ Auto-included via inference
CI setup? โโ GitHub Actions โ references/ci/github-actions.md โโ Vercel deployment โ references/ci/vercel.md โโ Remote cache in CI โ references/caching/remote-cache.md โโ Only build changed packages โ --affected flag โโ Skip unnecessary builds โ turbo-ignore (references/cli/commands.md) โโ Skip container setup when no changes โ turbo-ignore
Watch mode? โโ Re-run tasks on change โ turbo watch (references/watch/README.md) โโ Dev servers with dependencies โ Use `with` key (references/configuration/tasks.md#with) โโ Restart dev server on dep change โ Use `interruptible: true` โโ Persistent dev tasks โ Use `persistent: true`
Package creation/structure? โโ Create an internal package โ references/best-practices/packages.md โโ Repository structure โ references/best-practices/structure.md โโ Dependency management โ references/best-practices/dependencies.md โโ Best practices overview โ references/best-practices/README.md โโ JIT vs Compiled packages โ references/best-practices/packages.md#compilation-strategies โโ Sharing code between apps โ references/best-practices/README.md#package-types
Monorepo structure? โโ Standard layout (apps/, packages/) โ references/best-practices/README.md โโ Package types (apps vs libraries) โ references/best-practices/README.md#package-types โโ Creating internal packages โ references/best-practices/packages.md โโ TypeScript configuration โ references/best-practices/structure.md#typescript-configuration โโ ESLint configuration โ references/best-practices/structure.md#eslint-configuration โโ Dependency management โ references/best-practices/dependencies.md โโ Enforce package boundaries โ references/boundaries/README.md
Enforce boundaries? โโ Check for violations โ turbo boundaries โโ Tag packages โ references/boundaries/README.md#tags โโ Restrict which packages can import others โ references/boundaries/README.md#rule-types โโ Prevent cross-package file imports โ references/boundaries/README.md
Root package.json scripts MUST delegate to turbo run, not run tasks directly. // WRONG - bypasses turbo entirely { "scripts": { "build": "bun build", "dev": "bun dev" } } // CORRECT - delegates to turbo { "scripts": { "build": "turbo run build", "dev": "turbo run dev" } }
Don't chain turbo tasks with &&. Let turbo orchestrate. // WRONG - turbo task not using turbo run { "scripts": { "changeset:publish": "bun build && changeset publish" } } // CORRECT { "scripts": { "changeset:publish": "turbo run build && changeset publish" } }
Scripts like prebuild that manually build other packages bypass Turborepo's dependency graph. // WRONG - manually building dependencies { "scripts": { "prebuild": "cd ../../packages/types && bun run build && cd ../utils && bun run build", "build": "next build" } } However, the fix depends on whether workspace dependencies are declared: If dependencies ARE declared (e.g., "@repo/types": "workspace:*" in package.json), remove the prebuild script. Turbo's dependsOn: ["^build"] handles this automatically. If dependencies are NOT declared, the prebuild exists because ^build won't trigger without a dependency relationship. The fix is to: Add the dependency to package.json: "@repo/types": "workspace:*" Then remove the prebuild script // CORRECT - declare dependency, let turbo handle build order // package.json { "dependencies": { "@repo/types": "workspace:*", "@repo/utils": "workspace:*" }, "scripts": { "build": "next build" } } // turbo.json { "tasks": { "build": { "dependsOn": ["^build"] } } } Key insight: ^build only runs build in packages listed as dependencies. No dependency declaration = no automatic build ordering.
globalDependencies affects ALL tasks in ALL packages. Be specific. // WRONG - heavy hammer, affects all hashes { "globalDependencies": ["**/.env.*local"] } // BETTER - move to task-level inputs { "globalDependencies": [".env"], "tasks": { "build": { "inputs": ["$TURBO_DEFAULT$", ".env*"], "outputs": ["dist/**"] } } }
Look for repeated configuration across tasks that can be collapsed. Turborepo supports shared configuration patterns. // WRONG - repetitive env and inputs across tasks { "tasks": { "build": { "env": ["API_URL", "DATABASE_URL"], "inputs": ["$TURBO_DEFAULT$", ".env*"] }, "test": { "env": ["API_URL", "DATABASE_URL"], "inputs": ["$TURBO_DEFAULT$", ".env*"] }, "dev": { "env": ["API_URL", "DATABASE_URL"], "inputs": ["$TURBO_DEFAULT$", ".env*"], "cache": false, "persistent": true } } } // BETTER - use globalEnv and globalDependencies for shared config { "globalEnv": ["API_URL", "DATABASE_URL"], "globalDependencies": [".env*"], "tasks": { "build": {}, "test": {}, "dev": { "cache": false, "persistent": true } } } When to use global vs task-level: globalEnv / globalDependencies - affects ALL tasks, use for truly shared config Task-level env / inputs - use when only specific tasks need it
A large env array (even 50+ variables) is not a problem. It usually means the user was thorough about declaring their build's environment dependencies. Do not flag this as an issue.
The --parallel flag bypasses Turborepo's dependency graph. If tasks need parallel execution, configure dependsOn correctly instead. # WRONG - bypasses dependency graph turbo run lint --parallel # CORRECT - configure tasks to allow parallel execution # In turbo.json, set dependsOn appropriately (or use transit nodes) turbo run lint
When multiple packages need different task configurations, use Package Configurations (turbo.json in each package) instead of cluttering root turbo.json with package#task overrides. // WRONG - root turbo.json with many package-specific overrides { "tasks": { "test": { "dependsOn": ["build"] }, "@repo/web#test": { "outputs": ["coverage/**"] }, "@repo/api#test": { "outputs": ["coverage/**"] }, "@repo/utils#test": { "outputs": [] }, "@repo/cli#test": { "outputs": [] }, "@repo/core#test": { "outputs": [] } } } // CORRECT - use Package Configurations // Root turbo.json - base config only { "tasks": { "test": { "dependsOn": ["build"] } } } // packages/web/turbo.json - package-specific override { "extends": ["//"], "tasks": { "test": { "outputs": ["coverage/**"] } } } // packages/api/turbo.json { "extends": ["//"], "tasks": { "test": { "outputs": ["coverage/**"] } } } Benefits of Package Configurations: Keeps configuration close to the code it affects Root turbo.json stays clean and focused on base patterns Easier to understand what's special about each package Works with $TURBO_EXTENDS$ to inherit + extend arrays When to use package#task in root: Single package needs a unique dependency (e.g., "deploy": { "dependsOn": ["web#build"] }) Temporary override while migrating See references/configuration/README.md#package-configurations for full details.
Don't use relative paths like ../ to reference files outside the package. Use $TURBO_ROOT$ instead. // WRONG - traversing out of package { "tasks": { "build": { "inputs": ["$TURBO_DEFAULT$", "../shared-config.json"] } } } // CORRECT - use $TURBO_ROOT$ for repo root { "tasks": { "build": { "inputs": ["$TURBO_DEFAULT$", "$TURBO_ROOT$/shared-config.json"] } } }
Before flagging missing outputs, check what the task actually produces: Read the package's script (e.g., "build": "tsc", "test": "vitest") Determine if it writes files to disk or only outputs to stdout Only flag if the task produces files that should be cached // WRONG: build produces files but they're not cached { "tasks": { "build": { "dependsOn": ["^build"] } } } // CORRECT: build outputs are cached { "tasks": { "build": { "dependsOn": ["^build"], "outputs": ["dist/**"] } } } Common outputs by framework: Next.js: [".next/**", "!.next/cache/**"] Vite/Rollup: ["dist/**"] tsc: ["dist/**"] or custom outDir TypeScript --noEmit can still produce cache files: When incremental: true in tsconfig.json, tsc --noEmit writes .tsbuildinfo files even without emitting JS. Check the tsconfig before assuming no outputs: // If tsconfig has incremental: true, tsc --noEmit produces cache files { "tasks": { "typecheck": { "outputs": ["node_modules/.cache/tsbuildinfo.json"] // or wherever tsBuildInfoFile points } } } To determine correct outputs for TypeScript tasks: Check if incremental or composite is enabled in tsconfig Check tsBuildInfoFile for custom cache location (default: alongside outDir or in project root) If no incremental mode, tsc --noEmit produces no files
{ "tasks": { // ^build = run build in DEPENDENCIES first (other packages this one imports) "build": { "dependsOn": ["^build"] }, // build (no ^) = run build in SAME PACKAGE first "test": { "dependsOn": ["build"] }, // pkg#task = specific package's task "deploy": { "dependsOn": ["web#build"] } } }
// WRONG: API_URL changes won't cause rebuilds { "tasks": { "build": { "outputs": ["dist/**"] } } } // CORRECT: API_URL changes invalidate cache { "tasks": { "build": { "outputs": ["dist/**"], "env": ["API_URL", "API_KEY"] } } }
Turbo does NOT load .env files - your framework does. But Turbo needs to know about changes: // WRONG: .env changes don't invalidate cache { "tasks": { "build": { "env": ["API_URL"] } } } // CORRECT: .env file changes invalidate cache { "tasks": { "build": { "env": ["API_URL"], "inputs": ["$TURBO_DEFAULT$", ".env", ".env.*"] } } }
A .env file at the repo root is an anti-pattern โ even for small monorepos or starter templates. It creates implicit coupling between packages and makes it unclear which packages depend on which variables. // WRONG - root .env affects all packages implicitly my-monorepo/ โโโ .env # Which packages use this? โโโ apps/ โ โโโ web/ โ โโโ api/ โโโ packages/ // CORRECT - .env files in packages that need them my-monorepo/ โโโ apps/ โ โโโ web/ โ โ โโโ .env # Clear: web needs DATABASE_URL โ โโโ api/ โ โโโ .env # Clear: api needs API_KEY โโโ packages/ Problems with root .env: Unclear which packages consume which variables All packages get all variables (even ones they don't need) Cache invalidation is coarse-grained (root .env change invalidates everything) Security risk: packages may accidentally access sensitive vars meant for others Bad habits start small โ starter templates should model correct patterns If you must share variables, use globalEnv to be explicit about what's shared, and document why.
By default, Turborepo filters environment variables to only those in env/globalEnv. CI variables may be missing: // If CI scripts need GITHUB_TOKEN but it's not in env: { "globalPassThroughEnv": ["GITHUB_TOKEN", "CI"], "tasks": { ... } } Or use --env-mode=loose (not recommended for production).
// WRONG: Shared code inside an app apps/ web/ shared/ # This breaks monorepo principles! utils.ts // CORRECT: Extract to a package packages/ utils/ src/utils.ts
// WRONG: Reaching into another package's internals import { Button } from "../../packages/ui/src/button"; // CORRECT: Install and import properly import { Button } from "@repo/ui/button";
// WRONG: App dependencies in root { "dependencies": { "react": "^18", "next": "^14" } } // CORRECT: Only repo tools in root { "devDependencies": { "turbo": "latest" } }
{ "$schema": "https://turborepo.dev/schema.v2.json", "tasks": { "build": { "dependsOn": ["^build"], "outputs": ["dist/**", ".next/**", "!.next/cache/**"] }, "dev": { "cache": false, "persistent": true } } } Add a transit task if you have tasks that need parallel execution with cache invalidation (see below).
A dev task with dependsOn: ["^dev"] and persistent: false in root turbo.json may look unusual but is correct for turbo watch workflows: // Root turbo.json { "tasks": { "dev": { "dependsOn": ["^dev"], "cache": false, "persistent": false // Packages have one-shot dev scripts } } } // Package turbo.json (apps/web/turbo.json) { "extends": ["//"], "tasks": { "dev": { "persistent": true // Apps run long-running dev servers } } } Why this works: Packages (e.g., @acme/db, @acme/validators) have "dev": "tsc" โ one-shot type generation that completes quickly Apps override with persistent: true for actual dev servers (Next.js, etc.) turbo watch re-runs the one-shot package dev scripts when source files change, keeping types in sync Intended usage: Run turbo watch dev (not turbo run dev). Watch mode re-executes one-shot tasks on file changes while keeping persistent tasks running. Alternative pattern: Use a separate task name like prepare or generate for one-shot dependency builds to make the intent clearer: { "tasks": { "prepare": { "dependsOn": ["^prepare"], "outputs": ["dist/**"] }, "dev": { "dependsOn": ["prepare"], "cache": false, "persistent": true } } }
Some tasks can run in parallel (don't need built output from dependencies) but must invalidate cache when dependency source code changes. The problem with dependsOn: ["^taskname"]: Forces sequential execution (slow) The problem with dependsOn: [] (no dependencies): Allows parallel execution (fast) But cache is INCORRECT - changing dependency source won't invalidate cache Transit Nodes solve both: { "tasks": { "transit": { "dependsOn": ["^transit"] }, "my-task": { "dependsOn": ["transit"] } } } The transit task creates dependency relationships without matching any actual script, so tasks run in parallel with correct cache invalidation. How to identify tasks that need this pattern: Look for tasks that read source files from dependencies but don't need their build outputs.
{ "globalEnv": ["NODE_ENV"], "globalDependencies": [".env"], "tasks": { "build": { "dependsOn": ["^build"], "outputs": ["dist/**"], "env": ["API_URL", "DATABASE_URL"] } } }
FilePurposeconfiguration/README.mdturbo.json overview, Package Configurationsconfiguration/tasks.mddependsOn, outputs, inputs, env, cache, persistentconfiguration/global-options.mdglobalEnv, globalDependencies, cacheDir, daemon, envModeconfiguration/gotchas.mdCommon configuration mistakes
FilePurposecaching/README.mdHow caching works, hash inputscaching/remote-cache.mdVercel Remote Cache, self-hosted, login/linkcaching/gotchas.mdDebugging cache misses, --summarize, --dry
FilePurposeenvironment/README.mdenv, globalEnv, passThroughEnvenvironment/modes.mdStrict vs Loose mode, framework inferenceenvironment/gotchas.md.env files, CI issues
FilePurposefiltering/README.md--filter syntax overviewfiltering/patterns.mdCommon filter patterns
FilePurposeci/README.mdGeneral CI principlesci/github-actions.mdComplete GitHub Actions setupci/vercel.mdVercel deployment, turbo-ignoreci/patterns.md--affected, caching strategies
FilePurposecli/README.mdturbo run basicscli/commands.mdturbo run flags, turbo-ignore, other commands
FilePurposebest-practices/README.mdMonorepo best practices overviewbest-practices/structure.mdRepository structure, workspace config, TypeScript/ESLint setupbest-practices/packages.mdCreating internal packages, JIT vs Compiled, exportsbest-practices/dependencies.mdDependency management, installing, version sync
FilePurposewatch/README.mdturbo watch, interruptible tasks, dev workflows
FilePurposeboundaries/README.mdEnforce package isolation, tag-based dependency rules
This skill is based on the official Turborepo documentation at: Source: docs/site/content/docs/ in the Turborepo repository Live: https://turborepo.dev/docs
Workflow acceleration for inboxes, docs, calendars, planning, and execution loops.
Largest current source with strong distribution and engagement signals.