DEV Community

Cover image for From Nx to vx: keep the graph, drop the daemon
VX
VX

Posted on Edited on Originally published at vznjs.github.io

From Nx to vx: keep the graph, drop the daemon

One command writes native vx config from the graph your installed Nx
resolves. Targets that Nx plugins infer come along.

$ bunx @vzn/vx-migrate
  from      nx graph
  ran       bun add -d @vzn/vx @vzn/vx-lockfile @vzn/vx-history
  tasks     2 clean
  files     libs/ui/vx.config.ts
            apps/web/vx.config.ts
            .vx/workspace.ts
            .vx/.gitignore
  lock      2 project configs → .vx/projects.lock.json

  next      vx run build --all

$ vx run build --all
 ⏺︎     9ms success miss     ui#build
 ⏺︎     7ms success miss     web#build
$ rm -rf apps/web/dist && vx run build --all
  cache     local 1✓ 1↓
Enter fullscreen mode Exit fullscreen mode

Two Nx projects, Nx 24.0.1 · vx-migrate 69617eb · 2026-10-23

It reads the graph, not nx.json

diagram

import type { ProjectConfig } from '@vzn/vx/config'

export default {
  tasks: {
    build: {
      exec: {
        command: 'bun build src/index.ts --outdir dist',
      },
      dependsOn: ['^build'],
      inputs: {
        files: ['src/**/*'],
      },
      cache: {
        outputs: {
          files: ['dist'],
        },
      },
    },
  },
} satisfies ProjectConfig
Enter fullscreen mode Exit fullscreen mode

targetDefaults and namedInputs are already applied in the graph, so
each task gets its own values. In vx a shared list is an import.

To check first, bunx @vzn/vx init --keep writes only this:

import type { WorkspaceConfig } from '@vzn/vx/config'
import { nx } from '@vzn/vx-migrate'
import { npm } from '@vzn/vx-lockfile'
import { vxHistory } from '@vzn/vx-history'

export default {
  plugins: [
    nx(),
    npm(),
    vxHistory(),
  ],
} satisfies WorkspaceConfig
Enter fullscreen mode Exit fullscreen mode

Executors become commands, at your pace

{ "build": { "executor": "@nx/js:tsc", "options": { "main": "src/index.ts", "tsConfig": "tsconfig.lib.json" } } }
Enter fullscreen mode Exit fullscreen mode

Each becomes an nx-exec line that runs the executor through Nx's
public runExecutor, so nothing breaks on day one.

An executor target is written as its nx-exec line, and you rewrite it
as the real command when you want Nx gone:

build: {
  exec: { command: 'tsc -b tsconfig.lib.json' },
  inputs: { files: ['src/**', 'tsconfig.lib.json'] }, cache: { outputs: { files: ['dist/**'] } },
}
Enter fullscreen mode Exit fullscreen mode

These server executors come through as persistent tasks, and so does
any target Nx marks continuous:

  • @nx/vite:dev-server, @nx/vite:preview-server
  • @nx/webpack:dev-server, @nx/next:server
  • @nx/storybook:storybook, @nx/web:file-server
  • @nx/js:node, @nx/js:verdaccio
  • @angular-devkit/build-angular:dev-server

What maps

Nx vx
a project's targets tasks
dependsOn (^build, …) dependsOn, same syntax
inputs / namedInputs (resolved) inputs.files
{workspaceRoot}/file inputs.workspaceFiles
outputs cache.outputs.files
nx affected vx run … --affected[=<base>]
nx run-many --projects vx run … --filter
parallelism: false a TODO naming --concurrency 1
nx watch vx watch
targetDefaults already applied in the graph; share them as a preset you import

What replaces the rest

9,603 tasks, native config vx Nx 24.0.1
Nothing changed 799 ms 24.15 s
Cold build: CPU the runner burns 36.64 s 5 min 34 s

Synthetic monorepo, 1,601 projects · linux x64, 4 cores, concurrency 10 · vx 0be036747 · 2026-10-23 · benchmarks

  • The daemon: vx has none.
  • Distributed task execution: @vzn/vx-dte (alpha) on your own CI (how), or @vzn/vx-reapi on a Bazel pool.
  • Remote cache: nxCache() speaks the self-hosted /v1/cache wire.
  • Flaky tests: from local run history.
  • Graph view: vx run build --all --dry=json or vx show.

Generators have no vx replacement. Guide: Migrate from
Nx
. More at
vznjs.github.io/vx.


Originally published on the vx blog. vx is open-source (MIT) task orchestration with a build cache: vznjs.github.io/vx · GitHub.

Written with AI assistance.

Top comments (1)

Some comments may only be visible to logged-in visitors. Sign in to view all comments.