Monorepo & packages
Workspace members
Declare the packages in your monorepo with [workspace] members — glob patterns relative to the workspace root:
[workspace] members = ["apps/*", "packages/*"]
A directory matches only if it carries a recognised ecosystem marker (package.json, Cargo.toml, go.mod, pyproject.toml).
Fanning out with packages
A task's packages list fans it out across matching packages. Each package resolves the task independently — a bare task auto-detects that package's native runner:
[tasks.test] packages = ["apps/*", "packages/*"]
Add parallel = true to run the fan-out concurrently:
[tasks.test] packages = ["apps/*"] parallel = true
Matching: path glob or manifest name
Each packages entry matches against either:
a path glob (
apps/*), oran exact manifest name (
@scope/pkg).
Matching against manifest names is what allows faithful conversion of bun run --filter <name> style scripts.
[tasks."build:update"] packages = [ "@opentf/workeros-programs", "@opentf/workeros-coreutils", "@opentf/workeros-web", ]
The packages list matches manifest names; form-3 auto-detection resolves build:update to each package's native runner.
If a packages entry matches no workspace package, tsr exits with code 64 — it's almost always a typo.
Cross-package dependencies
Explicit cross-package edges use the pkg#task form and require no graph inference:
[tasks."web#build"] run = "vite build" dir = "apps/web" deps = ["ui#build"]
Topological deps
The package dependency graph and the upstream marker ^task have landed: tsr reads each package's manifest, resolves the edges between workspace members, and runs a fan-out in dependency order.
[tasks.build] packages = ["apps/*", "packages/*"] deps = ["^build"]
Every package's dependencies build before it does, a shared library builds once, and upstream packages are built even when the pattern didn't select them. See the graph docs for the full rules.
Running only what changed
tsr build --since main
--since restricts each fan-out to the packages affected by changes since a git ref — the packages that changed, plus everything that depends on them. Upstream dependencies are still built, so the run stays correct and not merely fast. See the graph docs for the full rules.