Turborepo
Rule
Scope: Monorepo tasks and package setup.
Just-in-Time Packages
- MUST: Export source TypeScript from packages via
exports(nodistbuilds). - SHOULD: Use source-mapped imports for better DX.
{
"name": "@project/utils",
"exports": {
".": "./src/index.ts",
"./*": "./src/*.ts"
}
}
Task Configuration
- MUST:
devtasks are persistent and uncached. - MUST:
build,typecheck,lint,testdepend on upstream (^task). - SHOULD: Keep
turbo.jsonminimal — only define tasks that need configuration.
Caching
- MUST: Declare
outputsfor every task that writes to disk ("outputs": ["dist/**"]). Without this, results aren't cached. - MUST: Include environment variables in
envkey so cache invalidates on change. UseglobalEnvfor variables affecting all tasks. - MUST: Add
.envfiles toinputs— Turbo doesn't auto-detect.envchanges. - SHOULD: Avoid root
.envfiles. Place them in packages that need them for explicit dependency tracking.
Package Configuration
- SHOULD: Use package-level
turbo.jsonwith"extends": ["//"]for package-specific overrides instead ofpackage#taskentries in root config. - MUST: Declare workspace dependencies in
package.json("@repo/types": "workspace:*") for^buildto trigger correctly.
CI
- SHOULD: Use
turbo run build(notturbo build) in scripts and CI for reproducibility. - SHOULD: Use
--affectedin CI to run only changed packages plus their dependents. - MUST: Use
pnpm install --frozen-lockfilein CI for reproducible builds.
Anti-Patterns
| Never | Why | Instead |
|---|---|---|
Chain with && in root scripts | Bypasses Turbo's dependency graph | Use turbo run |
prebuild scripts building deps | Duplicates Turbo's work | Declare package dependencies |
../ in inputs | Implicit cross-package deps | Use $TURBO_ROOT$/ |
--parallel flag | Ignores dependency order | Configure dependsOn |
| Cross-package relative imports | Tight coupling | Import from package entry points |