An input changes mid-run: what four task tools do
An input changes mid-run: what four task tools do
A file changes while a task runs. Does the cache save the output anyway? We read the source of vx, Turborepo, Nx and Vite Task.
vx clears a task’s declared outputs before it runs and after a hit, so a deleted file never lingers in dist and gets shipped.
After a cache hit, your output folder holds exactly what was cached. A
deleted file never lingers in dist/ and gets shipped.
$ echo "stale" > packages/a/dist/old.js$ ls packages/a/distindex.js old.js
$ vx run packages/a#build└─ packages/a#build ── (20ms) restored-local
$ ls packages/a/distindex.jsDemo workspace · vx 69617eb · 2026-10-23
flowchart LR M[cache miss] --> W1[delete current matches] --> R[run the task] --> S[save] H[cache hit] --> P[put cached files in place] --> W2[delete matches the entry lacks]
Before a miss runs, vx deletes what the output globs match. So an old
dist/old.js cannot be saved as new output. A hit moves each file into
place, so a reader never sees one missing.
$ vx lock✗ vx lock lock not written
packages/a#notes and packages/a#slow both write out/** / out/copy.ts vx clears a task's outputs before it runs, so one deletes the other's
fix give each task its own output pathOverlaps vx can prove are refused. Set rules.exclusiveOutputs: false
to let a later task add to an earlier one’s folder. It works, but its
own output path is faster.
vx records each output file (size, mode, mtime-ms, inode, ctime).
On the next hit, if the set and every file match, the restore is a few stats and no writes, and it is the no-op row in the benchmarks.
Their restore row deletes the outputs first, so every artifact is extracted, and it costs more.
.git, .vx and vx.lock.json.node_modules, unless a glob names it. node_modules/** is a legitimate output of an install task.A task with no cache: true owns nothing, and vx leaves its files
alone. More at vznjs.github.io/vx.