← Blog
The Nub Team

Nub 0.9.2

Gives the standalone runner a nubr command that runs a TypeScript file, a package.json script, or an installed bin.

Nub 0.9.2 adds nubr to the standalone runner, @nubjs/runner. It runs a TypeScript file, a package.json script, or an installed bin on plain Node, with no Nub binary anywhere.

Nub is an all-in-one toolkit for Node.js written in Rust. The nub command is flag-for-flag compatible with node, while adding full support for TypeScript, JSX, tsconfig.json, .env loading, and modern Web and ECMAScript APIs. It also includes a fast script runner (nub run), package runner (nubx), Node version manager (nub node), and pnpm-compatible package manager.

The unified runner

The standalone package puts Nub's TypeScript runtime on plain Node as an ordinary npm package — about 5 MB, with no package manager, no registry client and no network code in it. Until now it was a preload only: something you passed to node --import. It now ships a command too.

npm install --save-dev @nubjs/runner

The full CLI splits running things across three verbs. A package that ships a single bin has to unify them, so nubr covers all three:

nubr app.ts        # a file
nubr build         # a package.json script
nubr vitest run    # an installed node_modules/.bin entry

Names resolve most-specific-first — a file, then a script, then a bin. A script wins over a bin of the same name, matching npm, because a script usually wraps the bin it is named after. A directory comes last, so a build/ directory cannot shadow the build script.

Scripts run through the same shell npm uses, with node_modules/.bin on the path and pre/post hooks honored, and every Node process a script starts inherits the TypeScript support. An installed bin gets the same environment a script does; nothing is fetched from the registry, so the tool has to be installed already.

A file run re-execs Node with --import rather than arming the hooks in the current process. That costs about 30 ms and buys exactness: Module.runMain routes the entry through the CommonJS loader, which cannot load an ES module below Node 22.15, and a worker thread inherits its preload from the option store rather than from process.execArgv. Re-execing makes the command identical to the documented preload form by construction instead of by enumeration.

The preload is unchanged and still the right tool when the node invocation is not yours to change:

node --import @nubjs/runner app.ts           # one run
NODE_OPTIONS="--import @nubjs/runner" vitest # a tool that spawns node

The unified runner page documents the command, the preload, and the deployment shape. (#840)

Windows lifecycle scripts

A dependency's install script that assumes a POSIX shell now gets one on Windows: dependency lifecycle scripts run through the bundled busybox sh rather than cmd.exe. (#940)

The full release notes list every change in this release.

Get started

View repo