skills/turborepo/SKILL.md
Use when making Turborepo monorepo architecture decisions: choosing between monorepo vs polyrepo, deciding when to split packages, debugging cache misses, setting package boundaries, or avoiding circular dependencies. NOT for basic CLI syntax. Triggers on: turborepo, turbo cache miss, package boundaries, monorepo architecture.
npx skillsauth add acedergren/agentic-tools turborepoInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
4 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Assumption: You know turbo run build. This covers architectural decisions.
$ARGUMENTS: Monorepo decision, package boundary, or cache issue to analyze
/turborepo why is turbo cache missing in CI/turborepo should packages/ui be split from packages/web-core| Signal | Recommendation | | ------ | -------------- | | 1-3 engineers | Polyrepo — monorepo overhead not worth it | | <20% shared code | Polyrepo | | >50% shared code + frequent coordination | Monorepo compelling | | Mixed languages (Go/Python/JS) | Nx or polyrepo — Turborepo is JS/TS focused | | All builds <5min total | Overhead not justified yet | | Breaking changes require 3+ repos | Monorepo wins | | Services deploy independently | Polyrepo |
Break-even: Monorepo worth it when 3+ apps share 30%+ code AND frequent coordination is required.
The #1 Turborepo mistake: Putting task logic in root package.json.
// WRONG - defeats parallelization
// Root package.json
{ "scripts": { "build": "cd apps/web && next build && cd ../api && tsc" } }
// CORRECT - each package owns its task
// apps/web/package.json
{ "scripts": { "build": "next build" } }
// Root package.json - ONLY delegates
{ "scripts": { "build": "turbo run build" } }
Why: Turborepo can't parallelize sequential shell commands. Package tasks enable task graph parallelization.
Considering splitting code into a package?
│
├─ Used by 1 app only → DON'T split yet
│ └─ Keep in app; wait for second consumer
│ WHY: Premature abstraction, overhead > benefit
│
├─ Used by 2+ apps → MAYBE split
│ ├─ Stable API (rarely changes) → Split
│ ├─ Unstable (changes every sprint) → DON'T split yet
│ └─ Mixed team ownership → DON'T split (use import path)
│ WHY: Shared packages need stable APIs + clear owners
│
├─ Publishing to npm → MUST split
│
└─ CI builds > 10min → Split by stability, not domain
└─ Stable packages cache; unstable packages always rebuild
Anti-pattern: Creating packages for "clean architecture" with no consumers. Every package adds build, test, and version overhead.
Symptom: turbo run build fails with "Could not resolve dependency graph"
packages/ui → packages/utils
packages/utils → packages/ui // circular
Fix: Extract shared code to a third package (packages/shared).
For indirect cycles (A → B → C → A), use: npx madge --circular --extensions ts,tsx packages/
Symptom: Every feature touches 5+ packages; 10+ version bumps per sprint; pnpm workspace:* version hell.
Fix: Group by change frequency, not by domain:
packages/ui/ # All components (changes often)
packages/ui-primitives/ # Headless components (stable)
packages/icons/ # Generated SVGs (rarely changes)
Rule: Package boundary = different change frequency. Packages that always change together should be one package.
Symptom: Tests pass locally, fail in CI with "Cannot find module './dist/index.js'"
Cause: Tests run before build completes — race condition.
// WRONG - no dependsOn for test
{ "tasks": { "build": { "outputs": ["dist/**"] }, "test": {} } }
// CORRECT
{
"tasks": {
"build": { "dependsOn": ["^build"], "outputs": ["dist/**"] },
"test": { "dependsOn": ["build"] }
}
}
^build = build this package's dependencies first. build = build this package first.
Symptom: Cache never hits; every run rebuilds everything.
Cause: inputs glob too broad — comment changes trigger rebuild.
// WRONG
{ "build": { "inputs": ["src/**"] } }
// CORRECT
{ "build": { "inputs": ["src/**/*.{ts,tsx}", "!src/**/*.test.ts"] } }
Debug:
turbo run build --dry --graph # Visualize task graph
turbo run build --dry=json | jq '.tasks[] | select(.cache.status == "MISS")'
Starting new project?
│
├─ Single team, single product → Polyrepo (simpler)
│
├─ Shared UI library → Monorepo
│ └─ Develop library + test in consumers simultaneously
│
├─ Microservices in different languages → Polyrepo
│ └─ Turborepo is JS/TS focused
│
└─ Multiple teams, shared code, atomic changes needed → Monorepo
Practical advice: Start polyrepo, migrate to monorepo when the cross-repo coordination pain exceeds the tooling cost.
By stability (recommended):
packages/core/ # Changes quarterly (semantic versioning)
packages/features/ # Changes weekly (workspace protocol)
packages/utils/ # Changes monthly
By consumer:
packages/public-api/ # External consumers — strict versioning
packages/internal/ # Internal apps — workspace protocol OK
By team: Only works if teams rarely share code. Otherwise creates silos.
| Prefer Turborepo | Prefer Nx | Prefer Rush | | ---------------- | --------- | ----------- | | JS/TS monorepo | Project graph visualization needed | 100+ packages | | Vercel remote caching | Polyglot (JS + Python + Go) | Publishing to npm is primary goal | | pnpm/npm workspaces | Want opinionated project structure | Phantom dependency detection needed |
turbo run build --dry=json | jq '.tasks[0].hash' — see current hashinputs glob to exclude non-code files"cache": false in turbo.json temporarily to debug without cache pressureturbo run build --dry --graph=graph.html — visualize in browsernpx madge --circular --extensions ts,tsx packages/ — for indirect cyclespackages/sharedturbo run test --dry --graph — verify build runs before test"dependsOn": ["build"] to test taskturbo run test --force — bypass cache to confirm orderinggit log --oneline --since="1 month ago" -- packages/ — count version bumps per packageworkspace:* to auto-link versions while planning mergeREAD references/cli-options.md when: encountering 3+ unknown CLI flags, need advanced --filter patterns across 10+ packages, or setting up complex pipeline options.
READ references/remote-cache-setup.md when: setting up remote cache for teams, debugging cache auth errors, or configuring self-hosted cache with custom storage.
Do NOT load references for: basic architecture decisions, single cache miss debugging, or monorepo adoption decisions — all covered above.
development
--- name: api-audit description: "Use when auditing API routes for schema drift, missing auth, or validation gaps. Scans routes against shared TypeScript types to find mismatches, missing middleware, and undocumented endpoints. Read-only — produces a severity-grouped report. Keywords: audit routes, schema drift, auth gaps, missing validation, type mismatch, orphaned schemas. Triggers on "audit API routes" or "find schema drift"." --- # API Route & Type Audit Skill ## When to Use Load this skil
development
Use when drafting, translating, polishing, or reviewing Swedish text so it sounds natural, fluent, contemporary, and appropriate for its audience. Triggers include "write better Swedish", "make this sound natural in Swedish", "translate into Swedish", "polish this Swedish", "tech company Swedish", "contemporary Swedish words", "Swedish developer docs", and "avoid Anglicisms".
development
Use when working with shadcn-svelte components, TanStack Table in Svelte 5, or Tailwind v4.1. Covers non-obvious reactivity bugs, library selection trade-offs, and migration pitfalls not in the official docs. Keywords: shadcn-svelte, TanStack Table, Tailwind v4.1, Svelte 5 runes, bits-ui, superforms, data table, svelte-check.
data-ai
Use when mapping IDCS claims to org membership after OAuth login succeeds. Covers mapProfileToUser, session.create.before, session.create.after hooks, MERGE INTO upserts, tenant-org mapping, and first-admin bootstrap. Keywords: IDCS groups, org_members, provisioning, session hooks, tenant map, MERGE INTO.