A broken build skips what depends on it and nothing else. Every skipped task names the failure that blocked it. Pick fail-fast or run-everything with one flag, and set how many tasks run at once as a count or a share of the CPUs.
DX
DX
One package fails to build. What should happen to the other forty? vx’s
default: skip what needs the broken one, finish everything else, and
tell you which failure each skip is waiting on.
flowchart LR
U[ui#build fails] --> W[web#build skipped]
U --> D[docs#build skipped]
A[api#build] --> T[api#test]
style U stroke:#c6f84e,stroke-width:2px
@demo/ui has a type error. web and docs depend on it, api does
not:
Terminal window
$vxrunbuildtest--all
◼︎4msfailedmiss@demo/ui#build
⊘skipped@demo/docs#build•blockedby@demo/ui#build
⊘skipped@demo/web#build•blockedby@demo/ui#build
⊘skipped@demo/ui#test•blockedby@demo/ui#build
⊘skipped@demo/docs#test•blockedby@demo/ui#build
⊘skipped@demo/web#test•blockedby@demo/ui#build
⏺︎309mssuccessmiss@demo/api#build
⏺︎204mssuccessmiss@demo/api#test
┌─@demo/ui#build>failed (exit 1)
src/index.ts:3typeerror
└─@demo/ui#build── (4ms) failed (exit1)
api still built and tested. A skip two levels down, like web#test,
names the failure at the root of the chain, not the skip in between. You
fix one thing, not five.
deps-ok, the default: skip the failure’s dependents, run the rest.
never: fail fast. The first failure stops dispatch, running tasks
finish, and nothing new starts.
always, or bare --continue: run dependents anyway.
Terminal window
$vxrunbuildtest--all--continue=never
◼︎4msfailedmiss@demo/ui#build
⊘skipped@demo/web#build•blockedby@demo/ui#build
⏺︎308mssuccessmiss@demo/api#build
⊘skipped@demo/api#test
api#build was already running, so it finished. api#test never
started, and its skip has no blocker because nothing upstream failed. The
run simply stopped.
--concurrency caps the tasks that execute at the same time. It takes a
count or a share of the CPUs:
Terminal window
$vxrunbuild--all--concurrency8
$vxrunbuild--all--concurrency50%# half the CPUs, never below 1
$vxrunlint--all--concurrency200%# I/O-bound work can go over
The default is the core count, capped by the container’s CPU quota, so a
CI runner with a two-CPU limit does not start sixteen tasks. Set
concurrency in vx.workspace.ts to change the default for everyone.
Cache hits do not count against it. Restoring a hit is disk work, so hits
run on their own lane, up to twice the limit, and a warm run is not held
back by a budget meant for compilers.
A task hangs, gets killed, prompts for input, or calls vx run on itself. Each one gets a clear line from vx instead of a mystery. Plus timeouts, forwarded arguments, and two runs that politely take turns.
DX
Dev servers as graph nodes: readiness instead of sleep
The hard part of 'start the tests once the server is up' is knowing when it is up. vx watches a persistent task's output for a pattern, holds its dependents until the line appears, and tears the server down when the run ends.
vx watch does not filter filesystem events against your input globs. It re-runs the graph and lets the cache key decide, which is tens of milliseconds for an irrelevant edit and exactly right for a relevant one.
Turborepo, Nx and other product names are trademarks of their owners. vx is not affiliated with or endorsed by them.