Skip to content

Introduction

vx is a task runner and build cache for JavaScript monorepos. You describe each package’s tasks in a vx.config.ts; vx builds the dependency graph, runs tasks in parallel in the right order, and caches every result by the content of its inputs. Run the same thing twice and the second run replays from cache in milliseconds.

If you’ve used Turborepo or Nx, that shape is familiar. What’s different is the combination vx targets: Turborepo’s simplicity, more capability than either, and the fastest warm runs in the category — with no daemon and no plugins.

You’ll feel at home with vx if you are:

  • Hitting Turborepo’s ceiling. You love how simple it is, but turbo.json can’t express what you need, additive restores leave stale files in dist/, and the cache misses things your build actually depends on.
  • Tired of Nx’s weight. You want fast, correct caching without a long-running daemon, a plugin graph, generators, and a mental model that takes weeks to internalize.
  • Starting fresh and want something that stays out of your way: real TypeScript config, shell commands, one binary, no background process.

vx is deliberately shaped like Turborepo — per-package config, an opt-in content-addressed cache, a topological scheduler, the Turborepo remote-cache wire — with a few decisive swaps:

  • Your config is a program. vx.config.ts is real TypeScript. Imports, shared presets, and computed values all participate in the cache key (vx hashes the resolved config object, not the file bytes). Turborepo and Nx hash static JSON and miss this.
  • Sparse ^task bridging. ^build reaches through packages that don’t declare the task to the nearest dependency that does, so you don’t litter no-op tasks across the monorepo. Turborepo and Nx stop at direct dependencies.
  • Strict output ownership. Declared outputs are wiped before every build and every restore, so your working tree ends each run bit-identical to the cached snapshot. No stale stragglers, ever.
  • Daemonless. No background process, no staleness window, no socket state to corrupt — and still faster cold than Nx is daemon-warm.
  • Shell is the API. A task is a command string. There are no JS-function tasks and no executor plugin protocol to learn or maintain.

The full, sourced comparison lives in vx vs Turborepo vs Nx. The performance mechanics are in Why vx is fast.

vx is small on purpose. It deliberately has no generators or scaffolding, no plugin/executor protocol, no daemon, and no TUI. It doesn’t do dependency installation or version management — it runs and caches your tasks, and leaves the rest to the tools you already use. If you need code generation and an opinionated plugin ecosystem, Nx is the better fit and that’s fine.

  • Bun ≥ 1.3. vx is Bun-native — it ships as TypeScript that Bun runs directly, with no build step. There is no Node fallback.
  • git. vx uses git’s index to enumerate and hash inputs (the same technique Turborepo uses), so your workspace must be a git repository.
  • A pnpm / npm / yarn / Bun workspace — anything with a pnpm-workspace.yaml or a workspaces field. A single-package repo works too.