Package runner
Use nubx (or nub exec) to run the CLIs in your project's node_modules/.bin — a drop-in for npx and pnpm exec, an order of magnitude faster on cold start.
The nubx command runs the command-line tools your project already depends on — the ones installed into node_modules/.bin by pnpm, npm, yarn, or bun. It's a drop-in for npx and pnpm exec: it does the node_modules/.bin walk-up in Rust and exec's the resolved binary directly, so the wrapper overhead that npx and pnpm exec pay on every call (a full Node bootstrap) approximately disappears — ~17–20× lighter on a native CLI like esbuild. The tool that actually runs is identical to what npx would run; only the wrapper gets out of the way.
This page is task-oriented. For the bigger picture see the Introduction; for running files and scripts see running files and running scripts.
Run a local CLI
Point nubx at the bin name and let it resolve from node_modules/.bin. No node bootstrap in the wrapper, so resolution returns in single-digit milliseconds.
nubx eslint .
nubx prisma generate
nubx tscPass arguments
Everything after the bin name goes straight to the underlying tool, untouched. There is no -- separator to remember — nubx doesn't interpret your tool's flags.
nubx eslint . --fix --max-warnings 0
nubx tsc --noEmit
nubx prisma migrate dev --name init
nubx vitest run --coveragenub exec
Though nubx is a separate binary entry point, it's an exact alias for nub exec — same code path, same resolution, same behavior. Use whichever reads better in your context; nubx is shorter for the command line and shebangs, nub exec is natural inside a longer nub invocation.
nubx prettier --write .
nub exec prettier --write . # identicalHow bins resolve
Resolution walks node_modules/.bin/<name> starting from your current directory and moving upward through ancestor node_modules/.bin directories — the same chain nub run builds for PATH. In a monorepo that means the package member's own .bin is checked first, then the workspace root, then any further ancestors. This matches how npm, pnpm, yarn, and bun resolve bins, so a tool installed at the workspace root is reachable from any member.
# from packages/api in a monorepo:
# 1. packages/api/node_modules/.bin/<name>
# 2. <workspace-root>/node_modules/.bin/<name>
# 3. further ancestor node_modules/.bin directories
nubx tsc --buildThe resolved entry runs the right way for what it is: a Node script (a #!…node shebang or .js / .mjs / .cjs) runs through augmented node, a Windows .cmd / .bat via cmd /C, a .ps1 via PowerShell, and anything else (a native binary, or a non-node shebang like #!/bin/sh) execs directly.
--node
By default nubx runs the tool under Nub's augmentation — the PATH shim makes any node the tool spawns resolve back to Nub, with TypeScript transpilation and polyfills active. Pass --node to turn that off for the invocation: the bin's #!/usr/bin/env node shebang resolves to your real Node binary, no --import preload is added, and no experimental flags are injected. Reach for it when a tool's shebang chain needs byte-exact plain Node, when you're bisecting a Nub-vs-Node issue, or when CI wants exact Node runtime behavior with nubx's resolution.
nubx --node prisma generate
nub exec --node tsc --noEmitWhat still happens under --node: the workspace-aware node_modules/.bin walk-up, the not-installed message below, and nubx's own CLI machinery. Only the runtime augmentation is disabled. There is no NODE_COMPAT=1 env var — pass --node per invocation that needs it.
When a tool isn't installed
Already-installed bins are the whole scope — nubx does not fetch from the registry. If the bin isn't on the node_modules/.bin chain, nubx exits non-zero and prints a one-line suggestion. It detects your package manager from the nearest lockfile (pnpm-lock.yaml → yarn.lock → bun.lock → package-lock.json, falling back to a $PATH priority of pnpm > yarn > bun > npm) and points you at that PM's own dlx/exec verb — so installs and ad-hoc fetches stay in the tool that owns your lockfile, keeping it consistent.
$ nubx prettier
nubx: prettier is not installed locally.
Install it (pnpm add -D prettier) or run it ad-hoc with:
pnpm dlx prettierThe suggestion is printed, never run — you copy the command. The exact suggestion varies with the detected PM (pnpm dlx <pkg>, npx <pkg>, yarn dlx <pkg>, bunx <pkg>).
Version specifiers
Version specifiers like nubx prettier@3.5 are accepted, but they always miss the local-bin lookup — nubx doesn't match against installed versions. You'll get the not-installed message. Install the version you want, or run your PM's dlx verb directly.
pnpm add -D prettier@3.5 # then: nubx prettier
pnpm dlx prettier@3.5 # ad-hoc, no installYarn Plug'n'Play
Yarn Berry's Plug'n'Play mode replaces node_modules/.bin/ with a runtime resolution table managed by Yarn's own loader. Tools that walk the .bin/ tree — npx, pnpm exec, bunx, and nubx — don't see it. If you're on Yarn Berry and want nubx to resolve your bins, opt into the conventional layout by setting nodeLinker: node-modules in .yarnrc.yml.
# .yarnrc.yml
nodeLinker: node-modulesRelated
- Running files —
nub index.ts, TypeScript-first execution. - Running scripts —
nub run, the workspace-aware script runner that shares the.binresolution chain. - Watch mode —
nub watch, restart on change. - FAQ — short answers, including the
--nodeflag and the Yarn PnP caveat.
Script runnernub run
Use nub run as a drop-in for npm run / pnpm run — lifecycle hooks, npm_* env vars, arg forwarding, and pnpm-style workspace filters, an order of magnitude faster on the cold path.
Node managernub node
Manage the Node versions Nub provisions — pin a version and it's fetched automatically, or drive the cache explicitly with nub node install / ls / uninstall / pin.