Engineering

Turborepo Notes

Turborepo Notes

Project Creation Command

bunx create-turbo@latest

Personal takeaways from exploring a real project, for future blog write-ups.

1. What .npmrc Is

npm's runtime configuration file. Common uses: specifying registry mirrors, private-repo auth, workspace behavior, etc. In the current project .npmrc is empty, so npm falls back to global defaults.

2. What turbo.json Does

It's not "install turbo and you must add turbo.json" — rather, a Turborepo project treats turbo.json as its core task-scheduling manifest. Without it, the turbo command has no idea what to do.

Top-Level Fields

FieldMeaning
$schemaEditor validation spec; wrong values get red squiggles
ui: "tui"Terminal UI style (Turborepo 2.0 dashboard look)
tasksCore section: defines every available task and its scheduling rules

Task Fields Explained

"build": {
  "dependsOn": ["^build"],           // ^ = dependency packages; build deps first, then self
  "inputs": ["$TURBO_DEFAULT$", ".env*"],  // rebuild only when these files change
  "outputs": [".next/**", "!.next/cache/**"] // build artifacts to cache; ! means exclude
}
FieldDescription
dependsOnTask dependency graph; ^ prefix means a dependency package's task
inputsSource file set that determines cache invalidation
outputsBuild artifact paths Turbo will cache; for non-Next projects use dist/** etc.
cache: falseDo not cache (useful for dev tasks that change in real time)
persistent: trueLong-running process; Turbo won't wait for it to finish

Why the dev Task Is Special

"dev": {
  "cache": false,
  "persistent": true
}
  • cache: false: during development code changes constantly, so caching is pointless
  • persistent: true: the process stays alive (e.g. next dev), so it can't be a prerequisite for other tasks

3. Relationship Between workspaces and turbo.json

Key point: turbo does not define directory structure; it reuses npm workspaces' package discovery mechanism.

// root package.json
"workspaces": ["apps/*", "packages/*"]
  • npm workspaces answer "which packages exist"
  • turbo.json answers "how do we schedule scripts for those packages"

If you change workspaces to ["projects/*", "libs/*"], Turbo will look for packages there too. apps/ and packages/ are just community conventions.

4. Task Names Are Script Names, Not Package Names

Task names in turbo.json (build, lint, check-types, dev) must match the keys in each sub-project's package.json scripts section.

What happens when you run turbo run <task>:

  1. Scan every package declared in workspaces
  2. Find packages that have a matching <task> script
  3. Topologically sort by dependsOn and execute in parallel
  4. Packages without the script are silently skipped

Verified Example

Packagedev scriptlint scriptcheck-types script
web
docs
@repo/ui
@repo/eslint-config
@repo/typescript-config

Conclusions:

  • turbo run dev → only starts web + docs
  • turbo run lintweb + docs + @repo/ui lint together
  • turbo run check-typesweb + docs + @repo/ui type-check together
  • @repo/eslint-config has no scripts → ignored by every turbo task

5. Startup Command and Log Output

Command

npm run dev
# equivalent to: turbo run dev

Sample Output

• Packages in scope: @repo/eslint-config, @repo/typescript-config, @repo/ui, docs, web
• Running dev in 5 packages
• Remote caching disabled

docs:dev: cache bypass, force executing a749f20663826bcc
web:dev: cache bypass, force executing 787819e83b8ceec9

docs:dev: > docs@0.1.0 dev
web:dev: > web@0.1.0 dev

web:dev: ▲ Next.js 16.2.0 (Turbopack)
docs:dev: ▲ Next.js 16.2.0 (Turbopack)

web:dev: - Local:   http://localhost:3000
web:dev: ✓ Ready in 221ms

docs:dev: - Local:   http://localhost:3001
docs:dev: ✓ Ready in 221ms

Note: "in scope" lists all 5 packages, but "Running dev" only executes docs and web because only they have a dev script.

6. One-Sentence Summary

npm workspaces decide "which packages exist"; turbo.json decides "how to schedule scripts for those packages". Packages with matching scripts do the work; packages without them don't. outputs paths are fully customizable — set dist/** or .next/** according to your project type.

Recorded: 2026-05-27
Project: my-turborepo (npm workspaces + Turborepo)
Package manager: npm@11.12.1
Turbo version: ^2.9.15