Filters are unions
Separate --filter flags add up; braces intersect a path and diff.
From turborepo, filtering/patterns.md.
Apps that changed
ui and web changed. Dry-run a build of changed apps.
Two filtersBad
– in scopewanted 1
--filter=./apps/* --filter=[HEAD^1]One filter, bracesGood
– in scopewanted 1
--filter={./apps/*}[HEAD^1]Filter playground
Pick a filter to see what it selects.
--filter=web...Selects
turbo run build --filter=web... # web and what it depends on
turbo run test --filter=...ui # ui and what depends on it
turbo run test --filter=...^ui # only ui's dependents
turbo run build --filter=./apps/* --filter=!admin
turbo run build --filter={./apps/*}[HEAD^1] # intersection
turbo run build --filter=web... --dry # check before you run
Why it matters, pros and cons
Why it matters
Each --filter adds packages to the run. To keep only packages matching both a path and a change, both must sit in one filter.
Pros
- One flag says exactly which packages run.
...follows the graph both ways.--dryshows the scope before work starts.
Cons
- Brace syntax is easy to forget.
!only removes, it never adds.- For PRs,
--affectedis simpler.