Skip to content
vxvx
GitHubBlueskydev.toRSS
Releases

Starts 2× faster

turbo() now runs root tasks, single-package repos and with sidecars as Turbo does, nx() finds every project in an integrated repo, and the CLI starts 2× faster.

vx 0.0.242: Starts 2× faster

vx 0.0.200 to 0.0.242 shipped on 2026-09-29 and 09-30. Most of the batch makes turbo() and nx() from @vzn/vx-migrate run more real repos unchanged. Core also starts faster, saves misses faster, and tells you how to fix a task that rewrites its own input.

In this release

A //#format task in turbo.json used to need a vx.config.ts at the root, or vx run format --all said no project declares it. Core gained a discover stage, where a plugin names directories that become projects, and turbo() names the root when turbo.json declares a //# task. A single-package Turbo setup, with no workspaces at all, now maps its plain tasks to the root too. The two-line workspace file is all you need:

import type { WorkspaceConfig } from '@vzn/vx/config'
import { turbo } from '@vzn/vx-migrate'
export default { plugins: [turbo()] } satisfies WorkspaceConfig

PRs #1859, #1867. Deep dive: From Turborepo.

Turbo’s with key (web#dev with api#dev) was a todo, so starting web#dev started no API. Each persistent sidecar is now an edge: vx starts it and runs the task beside it. A task with no script of its own, like the dev in Turbo’s with-tailwind example, becomes a group that starts its sidecars.

Terminal window
vx run web#dev

PRs #1864, #1866. See Turbo and Nx config support.

Turbo env wildcards and framework prefixes

Section titled “Turbo env wildcards and framework prefixes”

Under turbo(), a * name in env or passThroughEnv (NEXT_PUBLIC_*) now expands over the run’s environment, as Turbo does, instead of leaving the task without those variables. Turbo 2’s framework inference applies too, so a Next.js build gets its NEXT_PUBLIC_* values and no longer inlines empty ones. A !NAME entry removes that name from the list.

Terminal window
NEXT_PUBLIC_API_URL=https://api.example.com vx run build --all

PRs #1896, #1897, #1881.

An integrated Nx repo keeps its project.json libraries out of the package manager’s workspace list. nx() attached only the ones that list named: 1 of analogjs’s 21 build tasks. It now names each graph node’s directory through the discover stage, so every project runs, and a root project needs no hand-written config. A warm nx() run also reuses core’s git status for its graph key instead of spawning its own.

Terminal window
vx run build --all

PRs #1862, #1901.

vx --version spent most of its time importing the run path. Every verb now loads on use, run included, so --version went from about 60 ms to 25 ms. A warm no-op run is unchanged.

Terminal window
vx --version
vx --version
before60 ms
after25 ms

PR #1883.

Each miss paid async round trips to check where its outputs live and to clean them before the task ran. Those now run synchronously for small sets. A full-miss run of 100 tasks went from 594 ms to 541 ms, and from 979 ms to 898 ms at --concurrency 1.

Terminal window
vx run build --all
Full miss, 100 tasks
before594 ms
after541 ms
Same, --concurrency 1
before979 ms
after898 ms

PRs #1885, #1898.

vx-reapi fails fast when the server is down

Section titled “vx-reapi fails fast when the server is down”

Every cache call spent 2.1 s backing off when the REAPI server refused the connection, so a five-task run took 24 s. Once one call has spent its retries, the next ones give up at the first refusal until the server answers again. The same run now takes 2.6 s and falls back to the local cache.

Terminal window
vx run build --all

PR #1887.

A hint for tasks that rewrite their inputs

Section titled “A hint for tasks that rewrite their inputs”

A task that rewrites one of its own inputs, like TanStack Router’s committed routeTree.gen.ts, is never saved: its key no longer describes the files. The status line named the file but not the fix. It now says to declare the file in cache.outputs:

Terminal window
[vx] app#build: `packages/app/src/routeTree.gen.ts` changed after its key was taken — the result stands, but is not saved under a key that no longer describes it; if the task writes it, declare it in cache.outputs

PR #1877.

Sandbox: gitConfig and writes outside the project

Section titled “Sandbox: gitConfig and writes outside the project”

allow.gitConfig was ignored, so .git/config stayed read-only to every sandboxed task. It now reaches the sandbox, for that task only. A dir/ write grant outside the project is created when missing, so a tool can fill a cold cache in your home. When a task fails, vx names the writes the sandbox refused outside the project and the directory to grant.

import { defineProject } from '@vzn/vx/config'
export default defineProject({
tasks: {
compile: {
exec: {
command: 'bun build --compile --target=bun-linux-x64 src/bin.ts',
sandbox: {
allow: {
network: ['registry.npmjs.org'],
write: ['~/.bun/install/cache/', '.*.tmp/**'],
},
},
},
},
},
})

PRs #1851, #1875. See What you can grant.

vx why --run and vx last accept the short id that vx last --list prints. The MCP tool whyDidThisRerun answered “not found” for it. It now resolves ids the same way the CLI does.

Terminal window
ok 2026-10-08T19:56:51.484Z 01a11d17-099c 1 task · 0 hits 148ms $ vx run build --all

PR #1888. Deep dive: Agents and MCP.

  • Plugins: PLUGIN_HOOKS gains discover, after config (#1859).
  • vx-mcp: whyDidThisRerun’s runId now takes a prefix (#1888).

See Upgrading.

Terminal window
npm install -D @vzn/vx@latest

A standalone binary updates itself with vx upgrade.

Turborepo, Nx and other product names are trademarks of their owners. vx is not affiliated with or endorsed by them.