Skip to content
vxvx
GitHubBlueskydev.toRSS
Releases

The Turbo and Nx flags you already type

vx 0.0.326 to 0.0.360 migrate Nx executor targets as the commands they run, accept the --filter and flag spellings Turbo, pnpm and Nx users already type, and cut a scoped run on 1,000 projects from 181 ms to 113 ms.

vx 0.0.360: The Turbo and Nx flags you already type

vx 0.0.326 to 0.0.360 all shipped on 2 October 2026. The theme is moving in: migrations write configs that run without Nx or Turbo installed, the CLI takes the selections you already know, and long-running dev servers behave. Windows is now supported through WSL only.

In this release

bunx @vzn/vx-migrate used to write every Nx executor target as an nx-exec line, so the migrated config still needed Nx to run. It now writes the command the executor drives, with the defaults Nx applies: jest, vitest, vite build, eslint, tsc, playwright, esbuild, swc, Next.js, Cypress, Storybook, and the Vite dev and preview servers. @nx/js:node becomes node on the build output, as a persistent task. Webpack and Rollup targets name Nx’s convert-to-inferred generator in their TODO, and nx-release-publish gets one note instead of a failing task per package. nx() still runs executors through nx-exec.

Terminal window
bunx @vzn/vx-migrate
vx run build --all

PRs #2298, #2333. Guide: Nx.

A task env that several packages share is now one export in vx-preset.ts instead of a copy in every config: vercel/ai’s output is 2× smaller, with every key unchanged. The .env probes are named exports too (dotenvFiles). Framework variables Turbo infers, such as Next’s NEXT_PUBLIC_*, are written out from the names your source and its workspace dependencies spell, so a migrated Next build no longer inlines them empty. The report also names the @vzn/vx-lockfile plugin your lockfile needs, and says when turbo() is redundant once the configs are written.

Terminal window
npx @vzn/vx-migrate

PRs #2207, #2217, #2218, #2225, #2319. Guide: Turborepo.

--filter now reads Turbo’s <name>...[ref] and ...x... forms as Turbo does, matches a name without its scope as pnpm does (cart finds @shop/cart), and lets a trailing ** in a path match its base directory. vx run takes Nx’s camelCase flags (--skipNxCache, --nxBail) and Nx short project names in cart:build. Every flag in Turbo 2.11’s run help now either works or is refused with the vx way to do it.

Terminal window
$ vx run build --heap
vx run: --heap (turbo): use `--profile[=<path>]` for vx's own trace (see `vx run --help`)

PRs #2015, #2016, #2017, #2018, #2041, #2055.

With no origin/HEAD (no remote, or the fetch actions/checkout does), a bare --affected compared with HEAD~1 and saw only a branch’s last commit. It now compares with the first trunk branch that is not HEAD, as Turbo and Nx do. On a one-commit shallow clone, vx says the history is missing instead of only that the ref did not resolve. Under turbo() on GitHub Actions, the base is the pull request’s base or the push’s before, as Turbo picks it.

Terminal window
vx run test --affected

PRs #2088, #2122, #2287.

A server vx keeps after the summary now streams its output line by line instead of showing nothing. One that crashes after the summary counts as failed in --summarize and --report. When another task in the run fails, vx stops the servers and exits 1 instead of holding them forever. vx run app#dev over a dependsOn: ['^dev'] group now keeps the servers it stands for.

Terminal window
vx run dev --all

PRs #2030, #2039, #2054, #2096. Deep dive: Dev servers in the graph.

A run scoped to one package no longer walks git over its whole dependency closure, only over the projects that own a task, and it finds that closure by search instead of building it for the whole graph. On 1,000 projects, a warm vx run build --filter pkg-500 went from 181 ms to 113 ms. A plain repository’s git facts are read off the disk instead of from a git rev-parse spawn, and a cold load imports 128 configs at a time.

A warm frozen run also keeps its lock check from one run to the next.

Terminal window
vx run build --filter pkg-500
Warm vx run build --filter pkg-500, 1,000 projects
before181 ms
after113 ms

PRs #2035, #2241, #2306, #2323, #2329.

The invocation line vx stores and vx last prints kept a secret passed after -- whole, while the task’s own output masked it. It is now masked with the same rule before it is recorded. --tag values, stored on the history row and sent to telemetry, are masked too.

Terminal window
vx run publish -- --token=$NPM_TOKEN
vx last

PRs #2307, #2337.

vx init now maps a script that runs a server as a persistent task, so a dependent no longer waits on it forever. A build’s output directory is guessed from its own command when no framework rule names one. The next: line it prints is runnable, naming git init first when needed. It names Yarn Plug’n’Play when that is why a config cannot load, and vx.config.cjs and vx.config.cts are read as configs.

Terminal window
vx init

PRs #2070, #2098, #2100, #2169, #2290, #2308.

A strace that warns it cannot check the seccomp filter order still works, but vx read the warning as a tracer failure and ran every sandboxed task twice. vx now uses such a strace only when it is quiet, and otherwise runs tasks untraced. A task with a port bridge also waits for its host listener before it starts, so a server’s port no longer refuses its first connection under load.

Terminal window
vx run test --all

PRs #2121, #2130. Deep dive: The sandbox.

Git 2.45 can store refs as a reftable (--ref-format=reftable). vx read HEAD from the ref files, which a reftable repository does not keep, and vx-migrate missed branch moves. Both now handle it; keys, cache hits and --affected match a normal repository.

Terminal window
git init --ref-format=reftable

PR #2318.

  • Native Windows is unsupported; run vx under WSL. Tasks no longer get SYSTEMROOT, APPDATA and the other Windows env vars (#2227).

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.