Node manager
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.
Nub runs your code on stock Node and provisions the right version for you. Pin a version, run a file, and the matching Node is downloaded and cached without a second command — the implicit path covers the common case completely, so you rarely manage versions by hand. The nub node subcommands exist for the cases the automatic path can't reach: warming the cache before you run, seeing what's installed, reclaiming disk, and recording a pin.
The whole group is optional — nub <file> behavior never changes whether you use it or not.
Versions install themselves
Drop a .node-version or .nvmrc in your project (or an engines.node range in package.json) and run nub. If that Node is already on your machine it's used as-is; if not, Nub downloads the matching stock build from nodejs.org — SHA-256 verified and cached under ~/.cache/nub/node — then runs your code in the same breath.
$ echo 22.15.0 > .node-version
$ nub index.ts
Using Node.js 22.15.0 (resolved from .node-version)
Installing from nodejs.org... (24 MB)
Installed in 8.0s
# ...your script runs, on exactly the Node you pinnedThis is the headline. Everything below is for when you want to do one of these steps deliberately instead of letting it happen on the next run. For the full provisioning story — precedence, the ~/.cache/nub layout, the per-invocation shim — see Running files → The Node version.
nub node install
Provision a version into the cache now, instead of on the next nub <file>. The use cases are warming a CI cache in a setup step, or fetching a Node before you go offline.
nub node install 22 # newest 22.x
nub node install lts # newest LTS line
nub node install 20.11.0 # an exact version
nub node install 20 22 # several at onceAliases and ranges resolve the same way pins do — lts, latest, lts/<codename>, a bare major (22) or major.minor (22.13), or an exact version. With no argument, nub node install reads your project's pin and provisions that:
nub node install # installs whatever .node-version / .nvmrc / engines.node namesIt's idempotent and frugal. A version already in the cache is a no-op; a version already available on your PATH (a system install, nvm, fnm, …) is reported and skipped rather than re-downloaded — there's nothing to gain from a second copy.
$ nub node install 22.15.0
Node 22.15.0 is already available on PATH — skippednub node ls
List the versions in Nub's cache, newest first. The version your current directory resolves to is marked.
$ nub node ls
→ 22.15.0
22.13.0
20.11.0Only Nub's own download cache is shown — ls doesn't enumerate your nvm / fnm / system installs, because Nub doesn't manage those stores. The → marker appears only when the resolved version is one Nub has cached.
nub node uninstall
Reclaim disk by deleting a cached version. Nub guards against removing the version your current directory resolves to.
$ nub node uninstall 20.11.0
Removed Node 20.11.0 from the cacheLike ls, this operates on Nub's cache only — it will never touch a version nvm or your system package manager installed.
nub node pin
Write a .node-version for the project so every later nub in that tree uses it. This is the explicit form of creating the pin file by hand.
$ nub node pin 22
pinned Node 22 → /path/to/project/.node-versionA few deliberate behaviors:
- It pins the project, not the subdirectory. Run from anywhere inside the project and the file lands at the project root — the nearest
package.jsondirectory — not in your current subfolder. - In a workspace, it pins the whole repo. A Node version is a property of the repository, not one package, so in a monorepo the pin is written at the workspace root. (A single package can't run on its own Node anyway — resolution walks up, so a member-level pin wouldn't reach its siblings.)
- It edits the pin file you already have. If the project carries a
.nvmrcbut no.node-version,pinupdates the.nvmrcin place rather than dropping a second file that would silently shadow it. - It always prints where it wrote. No guessing which file changed.
Whatever spec you give is written verbatim — including an alias like lts — and pin never hits the network, so it's instant and works offline. The .node-version file is the tool-agnostic convention (nvm, fnm, volta, asdf all read it), so the pin is portable to your other tools, not just Nub.
Mirrors and proxies
Corporate network? Node downloads honor HTTP(S)_PROXY/NO_PROXY, and corporate TLS-intercepting CAs work out of the box (system trust roots). To fetch Node from an internal mirror instead of nodejs.org, set the standard env var or the .npmrc key pnpm uses — Nub reads both, no Nub-specific config:
# .npmrc (project or ~)
node-mirror:release=https://artifactory.corp.example/node/NODEJS_ORG_MIRROR (the nvm/n convention) takes precedence when set. An explicit mirror is used for musl builds too — point it at a mirror that carries the unofficial-builds layout on Alpine.
Bring your own version manager
With no pin file, Nub adopts whatever node is on your PATH. Switch versions with nvm, mise, fnm, brew, or the official installer and Nub picks up the active one — it doesn't install a "default" Node of its own and won't shadow the version manager you already use. Nub has no user-level config file; outside a pinned project, your shell's node is the answer.
nvm use 24
nub node which # prints the exact Node binary Nub will spawn hereThe quickest way to answer "which Node runs here, and where is it?" is nub node which — it prints the resolved binary path to stdout (so NODE=$(nub node which) captures just the path), with a » resolved from <source> explainer on stderr, whether the version came from a pin, the cache, or your PATH. Bare nub node reports the same as a status block.
A deliberately small surface
Five verbs — which, install, ls, uninstall, and pin — are the whole group (plus bare nub node for a status readout). There's deliberately no ls-remote, no prune, --force, custom aliases, or a global-default command — the automatic provisioning covers the common path, and the small surface keeps "you don't have to think about Node versions" true.
Related
- Running files — how provisioning fires during a normal
nub <file>run. - FAQ — supported Node floor and compatibility.
Package runnernubx
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.
Package meta-managernub pm
Provision and run the package manager your project pins — corepack's job, in native Rust. Pin a version and the exact pnpm/npm/yarn is fetched, verified, cached, and run on the project's Node.