README.md
July 13, 2026 Β· View on GitHub
Nub
A fast all-in-one toolkit that augments Node.js instead of replacing it
A Bun-like DX on top of stock node, written in Rust.
nub index.ts # TypeScript-first Node.js runtime
nub run dev # 24Γ faster pnpm run
nubx prisma generate # 19Γ faster npx
nub install # 18Γ faster pnpm install
nub watch src/server.ts # native watch mode
nub pm shim # built-in Corepack-style shims
nub node install 26 # Node version manager
nub upgrade # self update
One tool to run your files and scripts, install dependencies, and manage Node itself. No new runtime, no vendor-specific API surface, no lock-in.
| Nub | Instead of |
|---|---|
nub <file> | node, tsx, ts-node, dotenv-cli |
nub run <script> | npm run, pnpm run |
nubx | npx, pnpm dlx / exec |
nub install | npm, pnpm |
nub watch | nodemon, node --watch, tsx watch |
nub node | nvm, fnm, n, volta |
nub pm | corepack |
Install
# macOS / Linux
curl -fsSL https://nubjs.com/install.sh | bash
# Windows (PowerShell)
irm https://nubjs.com/install.ps1 | iex
# Homebrew (macOS / Linux)
brew install nubjs/tap/nub
# Nix (flakes)
nix run github:nubjs/nub
# mise
mise use -g nub
# Or via npm (pnpm / yarn global add work too)
npm install -g --ignore-scripts=false @nubjs/nub
For GitHub Actions, use nubjs/setup-nub in place of actions/setup-node. It's one-to-one compatible.
- - uses: actions/setup-node@v4
+ - uses: nubjs/setup-nub@v0
File runner β nub <file>
Run a file. Supports .js, .ts, .mjs, .cjs, .mts, .cts, .jsx, and .tsx. Flag-for-flag and var-for-var drop-in compatible with node (mostly via passthrough).
nub index.ts # TypeScript, JSX, no build step
nub --watch app.ts # same path, restart-on-change
It augments stock Node with some of Bun/Deno's best features:
- π¦ Full TypeScript support, including
enum,namespace - π§ TypeScript-friendly resolution: extensionless imports,
tsconfig.json#paths - βοΈ JSX / TSX
- π Decorators and
emitDecoratorMetadata - π Modern syntax like
using(downleveled in transpiler when needed) - π Automatic
.env*loading β Next.js/Vite parity - ποΈ Built-in loaders for common data formats β
.yaml,.toml,.jsonc,.json5,.txt - π Polyfills for
Temporal,Worker,URLPattern(when needed) - π₯ Unflags experimental features likeΒ
node:sqlite,vm.Module,localStorage,WebSocket,EventSource - β‘ 2.9Γ faster startup than
tsx
How it works βΒ Nub takes advantage of Node extension surfaces that mostly didn't exist when Deno and Bun were built:
--import/--requirepreloadsmodule.registerHooks()for transpilation and resolution- N-API native addons: Nub embeds oxc for pre-transpilation
Node provisioning
When you run a file with nub, it infers the version of Node your project expects and auto-installs it if needed. It respects (in precedence order):
NODE_EXECUTABLE(override)package.json#devEngines.node-version.nvmrcpackage.json#engines
This resolved version of Node is installed and your file is executed with it (with Nub's augmentations).
$ echo 26 > .node-version
$ nub hello.ts
Using Node.js 26.3.0 (resolved from .node-version)
Installed in 9.8s
Hello world!
Modern APIs
Modern API work out of the box under Nub. Node.js experimental APIs are unflagged, others are auto-polyfilled (e.g. Temporal on Node 25 and earlier), and others are downleveled in the transpiler (using).
| API | How |
|---|---|
Temporal | polyfilled below Node 26, native above |
URLPattern | polyfilled below Node 24, native above |
RegExp.escape | polyfilled below Node 24, native above |
Error.isError | polyfilled below Node 24, native above |
Promise.try | polyfilled below Node 24, native above |
Float16Array | polyfilled below Node 24, native above |
navigator.locks | polyfilled below Node 24.5, native above |
reportError | polyfilled |
vm.Module | unflagged |
Wasm module imports | unflagged below Node 24.5 (22.19 on the 22.x line), native above |
WebSocket | unflagged from Node 20.10, native from Node 22 |
EventSource | unflagged from Node 20.18, native above |
node:sqlite | unflagged from Node 22.5, native from Node 22.13 |
addon imports | unflagged from Node 22.20, never native |
Watch mode
Restart-on-change driven by the resolved dependency graph plus the off-graph files that still invalidate a run β no glob list to maintain:
nub watch src/server.ts
nub --watch src/server.ts # same path
- π Tracks the resolved dependency graph automatically
- π§· Also watches the off-graph invalidators β
.env*, thetsconfig.jsonextends chain,package.json - βοΈ Runs on Node's own
--watchengine, preserving output by default
View the full runtime docs π.
Script runner β nub run
A drop-in for npm run and pnpm run. The runner is a Rust binary with no JavaScript startup of its own, so it dispatches a warm script roughly 24Γ faster than pnpm run:
nub run build
nub run -r --filter "@org/*" test # supports --filter
It's fast compared to existing JavaScript-based script runners.
| Command | Time | Relative |
|---|---|---|
nub run | 14.7 ms | β |
npm run | 329.9 ms | 22Γ |
pnpm run | 442.7 ms | 30Γ |
script dispatch Β· warm Β· 50 runs Β· macOS β view benchmark
- π Feels instantaneous β 14ms vs a detectable 300ms+ lag for npm/pnpm
- π Full lifecycle support β
pre/posthooks and the completenpm_*environment - π§° Local
node_modules/.binonPATH, with args forwarded without the--separator - ποΈ The full pnpm workspace surface β
-r,--filter,--parallel,--workspace-concurrency,--resume-from,--stream - π― pnpm's
--filtergrammar verbatim β graph (...@org/web) and changed-since ([main]) selectors
View the full script runner docs π.
Package runner β nubx / nub dlx
A drop-in for npx and pnpm dlx. Local-first with a download-and-execute registry fallback (same as npx). Eliminating the double-Node.js-spawn performance penalty paid by JavaScript-based tools like npx and pnpm.
nubx eslint . --fix
nubx -y cowsay@1.5.0 "hi" # fetched from the registry (auto-approved via -y)
| Command | Time | Relative |
|---|---|---|
nubx esbuild --version | 11 ms | β |
| `pnpm exec esbuild --version$ | 191 \text{ms} | 17 \times |
| $npx esbuild --version` | 226 ms | 19Γ |
esbuild --version Β· macOS β view benchmark
- β‘ Runs a local bin ~19Γ faster than
npx, with no Node in the wrapper - π Resolves
node_modules/.binregardless of which package manager installed it - π Registry fallback for uninstalled bins β fetched, run, then discarded
- π§© Full
pnpm exec/pnpm dlxflag parity, shell mode included - πͺ Walks the resolution chain β member
.bin, then workspace root, then ancestors
View the full package runner docs π.
Package manager β nub install
Nub is a package manager powered by the Aube engine. The CLI is flag-for-flag compatible with pnpm for muscle memory, but
nub install
nub ci
nub add -E -D --save-catalog react
nub remove lodash
nub update
nub dedupe
It's fast β avoids the per-command Node.js bootstrap lag incurred by JS-based package managers.
| Tool | Time | Relative |
|---|---|---|
nub | 171 ms | β |
bun | 686 ms | 4.0Γ |
pnpm | 3193 ms | 18.7Γ |
npm | 5316 ms | 31.1Γ |
warm frozen install Β· TanStack Start Β· 313 deps Β· macOS β view benchmark
Security
- π‘οΈ Blocks postinstall by default
- π¦ Checks osv.dev for known-malicious package versions during resolution by default
- π» Refuses provenance downgrades by default
- β³ 24-hour
minimumReleaseAgeby default
Compatibility
When you run nub install inside a project, it detects the incumbent package manager (based on your package.json#packageManager or any detected lockfiles). It then runs in compat-mode, respecting the config files and environment variables for that package manager.
Under each incumbent, Nub reads that tool's branded config and no other's; the neutral .npmrc cascade and npm_config_* are read under every one.
| Incumbent | Config it reads |
|---|---|
| npm | package-lock.json, .npmrc, overrides, workspaces, engines/os/cpu/libc |
| pnpm | pnpm-lock.yaml, pnpm-workspace.yaml, .pnpmfile.cjs, package.json#pnpm, resolutions, catalog:, .npmrc |
| Yarn (read-only) | yarn.lock, a .yarnrc.yml / .yarnrc subset, YARN_*, resolutions, packageExtensions, .npmrc |
| Bun | bun.lock, bunfig.toml [install], trustedDependencies, overrides, patchedDependencies, catalog:, .npmrc |
| Nub | neutral only β .npmrc, npm_config_*, overrides / resolutions / catalog / workspaces |
View the full package manager docs π.
Package meta-manager β nub pm
Corepack's job, in native Rust: provision and run the exact pnpm / npm / yarn your project pins:
nub pm shim # registers global shims (Corepack-style)
Like corepack enable, this registers global shims for npm, yarn, and pnpm. When you run a command using one of these shim aliases anywhere on your file system, the shim will:
- Detect the version used in your project
- Install that version if needed
- Run the command using the proper version
Nub provides this functionality as a convenience for users who prefer to keep their current package manager. Corepack itself was unbundled from Node itself in v25.
View the full nub pm docs π.
Node version manager β nub node
Though Node.js versions will generally be auto-installed and cached as needed, you can manage versions manually as well.
$ nub node -h
nub node β manage Node versions
Usage: nub node <command>
Commands:
which print the resolved Node binary path (why β stderr)
install [<version>...] provision version(s) into nub's cache
ls list versions in nub's cache
uninstall <version> remove a version from nub's cache
pin <version> write the project's Node pin
View the full nub node docs π.
License
MIT
βοΈ If you read this far, consider starring the repo :) βοΈ