Aquí hi ha 24 versions de Nub, des de 17 de juny del 2026 fins a l’actual, 0.9.7. Cadascuna enllaça amb els instal·ladors del mateix desenvolupador.
| Versió | Data | Mida | Fitxers |
|---|---|---|---|
| 0.9.7Darrera versió | 19 d’octubre del 2026 | — | 64 bits ZIPARM64 ZIP Notes de la versióNub 0.9.7 runs each nub --test file once again, keeps the full manifest of URL, git and file: dependencies, and fixes two compat-mode launch failures.
Runtime
──────────────────────┬──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┬───────────────────────────
Area │What changed │Link
──────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼───────────────────────────
nub --test │Each test file runs once. 0.9.5 and 0.9.6 ran every test file twice. │#993
──────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼───────────────────────────
Threadpool startup │libuv's threadpool is built on a private loop, so user code no longer sees a startup fs.access request: process.getActiveResourcesInfo() and async_hooks match plain Node, and the event loop exits on the same │#993
│turn. │
──────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼───────────────────────────
Deleted array iterator│A script that deletes Array.prototype[Symbol.iterator] and then imports a module no longer crashes in Nub's load hook. │#993
──────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼───────────────────────────
Nested invocations │A nub command started beneath the node shim, --node or nodeCompat runs as Nub instead of on plain Node. A NODE_COMPAT set by the user is honored as before. │#1006, fixes #1005
──────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼───────────────────────────
Compat mode on macOS │With TMPDIR unset, a compat-mode run could exit with code 137 before Node started. │#1007
──────────────────────┴──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┴───────────────────────────
Package manager
URL tarball, git and file: dependencies keep their whole manifest during resolution (#963).
- optionalDependencies are filtered by platform, required peers are installed, bundled dependencies are not re-resolved, and os, cpu and libc apply, as they do for registry packages.
- nub.lock and the other portable lockfiles record every platform's optional URL tarball with its integrity, as npm and pnpm do. Only the host's variant is installed. An optional URL tarball that fails to download is skipped with a warning.
- A direct URL package keeps its platform and peer metadata after the lockfile is written and read back.
- Two nub.lock round-trip failures are fixed: a long URL-keyed entry was written on one line and failed the next install with expected struct RawSnapshot, and a scoped URL dependency was read as an npm alias (npm-alias references missing package).
Testing and internals
- A project preload is tested beneath a compat launch and under nub watch (#1009).
- The winget manifest fixture tracks 0.9.6 (#996), and the winget-releaser pin names the commit its v2 tag now points at (0260adb).
- A benchmark measures request and event-loop latency of the threadpool |
| 0.9.6 | 1 d’octubre del 2026 | — | 64 bits ZIPARM64 ZIP Notes de la versióNub 0.9.6 brings the iterator chunking, includes and join helpers in line with their Stage 4 specifications, and the stable release run now waits for the maintainer's approval of the staged npm versions.
Runtime
The Iterator.prototype helpers chunks, windows, includes and join follow the Stage 4 text of the iterator chunking, iterator includes and iterator join proposals (#988).
────────────────────────────────┬────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Change │Detail
────────────────────────────────┼────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
windows(size, undersized) │A second argument, "only-full" (the default) or "allow-partial", decides whether an iterator shorter than size yields one short window.
────────────────────────────────┼────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
includes(value, skippedElements)│A second argument skips that many values before the search starts.
────────────────────────────────┼────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Argument validation │A size or skip count is no longer coerced: a non-integral number throws a TypeError. The arguments are checked before the first next call, and a failed check closes the
│receiver.
────────────────────────────────┼────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
join │Values are converted with ToString, as Array.prototype.join does.
────────────────────────────────┼────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Promise.try │The polyfill constructs its result from this, so a subclass receives an instance of itself.
────────────────────────────────┴────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
On Node 26.7 with the native methods removed, the test262 built-ins/Iterator and Promise/try suites pass 1180 of 1338 tests, up from 922. The four methods pass all 140 of their tests on Node 18.19 through 26.7. @nubjs/types declares the two new optional parameters.
Documentation
- The install pages note that mise puts nubr on PATH alongside nub and nubx (1faa08a).
- The resolution page describes the nub export condition as a condition the CLI sets, without a registration claim (ea2eb52).
Release pipeline and packaging
- A stable release run is held on the release-approval environment after the npm packages are staged, and resumes when the maintainer approves the staged versions (#981). The staging script resolves a package's directory before it reads the package's package.json (5727154).
- The winget manifest fixture tracks 0.9.5 and points nubr at its own bin
ubr.exe (#989).
What's Changed
- winget: the fixture tracks 0.9.5 and points nubr at its own bin
ubr.exe by @colinhacks in #989
- release: hold the run on the release-approval environment until the staged versions are approved by @colinhacks in #981
- runtime: iterator chunking/includes/join polyfills follow the Stage 4 spec by @colinhacks in #988 |
| 0.9.5 | 25 de setembre del 2026 | — | 64 bits ZIPARM64 ZIP Notes de la versióWhat's Changed
- node: resolve alias pins against the cached dist index in the offline discovery path by @colinhacks in #966
- linker: never hoist a package where it shadows a dependency the parent resolves above by @colinhacks in #965
- actions: npm-ci, the npm ci step on Nub's engine by @colinhacks in #967
- Cleanup bad commits by @colinhacks in #972
- release: stage npm packages through OIDC and wait for a 2FA approval by @colinhacks in #973
- release: start a stable release from a workflow_dispatch and create the tag in the run by @colinhacks in #975 |
| 0.9.3 | 19 de setembre del 2026 | — | 64 bits ZIPARM64 ZIP Notes de la versióThe nub binary answers to nubr, so every install channel that puts nub and nubx on the path now puts the unified runner there too.
nubr on every channel
0.9.2 introduced nubr as the bin of @nubjs/runner on npm. This release makes the same command a third name on the nub binary: invoked as nubr, it runs the nubr.mjs the binary already embeds, on the project's Node, provisioning one when none is installed. The npm package and the binary run the same file, so a project behaves the same under either.
curl -fsSL https://nubjs.com/install.sh | bash # macOS / Linux
irm https://nubjs.com/install.ps1 | iex # Windows (PowerShell)
nubr app.ts # a file
nubr build # a package.json script
nubr vitest run # an installed node_modules/.bin entry
───────────────────────┬──────────────────────────────────────────────────────────────────────────────────────────────────────────
Channel │What changed
───────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────
install.sh / │Create nubr beside nubx; the uninstall paths remove it
install.ps1 │
───────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────
nub upgrade │Recreates the nubr alias on Unix and refreshes nubr.exe on Windows
───────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────
Homebrew tap │The generated formula symlinks nubr and asserts nubr --version
───────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────
@nubjs/nub on npm │Ships a nubr bin next to nub and nubx
───────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────
Nix flake │Adds the symlink and an apps.nubr entry
───────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────
winget │The committed Nub.Nub fixture registers nubr as a third alias of the one nub.exe, and CI proves all three
│run
───────────────────────┴──────────────────────────────────────────────────────────────────────────────────────────────────────────
nubr --version prints the bare version, matching the npm command. (#943, adfdba73ce)
winget
Nub has been published on winget as Nub.Nub since 0.1.0 and is bumped by community automation on each release; winget install Nub.Nub is now in the README. The in-repo fixture tracks that identifier at 0.9.2, and the release workflow's own submission job stays a dormant fallback. (#944, 4a0f4dc5e3)
Configuration
Note
The string form of prefix refuses a backslash. The string is split like a POSIX shell, so "C:\\tools\\wrap.exe --" reached the launch as C:toolswrap.exe. The error names the array form, which takes each argument as written. The published schema carries the same rule. (#941, 66af607145)
Documentation
──────────────┬────────────────────────────────────────────────────────────────────────────────────────────────────────────────┬───────────────
Area │What changed │Commit
──────────────┼────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼───────────────
Unified runner│New "From the nub installer" section, a nubr section in the README, and the install page lists all three │adfdba73ce
│commands │
──────────────┼────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼───────────────
Resolution │The nub export-condition example points at JavaScript, since files under node_modules are never transpiled │921f4def52
──────────────┼────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼───────────────
Extensions │The @nubjs/extensions page is removed and its URL redirects to the package's own repository │483eaa84ff
──────────────┼ |
| 0.9.2 | 13 de setembre del 2026 | — | 64 bits ZIPARM64 ZIP Notes de la versióThe standalone loader package is renamed to @nubjs/runner and gains nubr, a command that runs a TypeScript file, a package.json script, or an installed bin.
Important
The standalone loader package moved. @nubjs/loader and its eight platform packages are now @nubjs/runner and @nubjs/runner-*. The old packages stay on the registry at 0.9.1 and stop receiving updates, so switch the dependency and any --import flag over:
-npm install --save-dev @nubjs/loader
+npm install --save-dev @nubjs/runner
-node --import @nubjs/loader app.ts
+node --import @nubjs/runner app.ts
Nothing else about the preload changed — the entry points, the hooks and the resolution behavior are the same.
The unified runner
The package now ships a command as well as a preload. One name covers the three things the full CLI splits across nub <file>, nub run and nubx, because a package with a single bin has to unify them:
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.
Scripts run through the same shell npm uses, with node_modules/.bin on the path and pre/post hooks honored. A file run re-execs Node with --import rather than arming the hooks in-process, so the command is identical to the documented preload form by construction. (#840, 04929a4b9b)
Package manager
─────────────────────────┬───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┬───────────────────────────
Area │What changed │Commit
─────────────────────────┼───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼───────────────────────────
Windows lifecycle scripts│Dependency lifecycle scripts run through the bundled busybox sh, so a package whose install script assumes a POSIX shell behaves the same on │cb0e091780 (#940)
│Windows │
─────────────────────────┴───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┴───────────────────────────
Documentation
─────────────────────┬────────────────────────────────────────────────────────────────────────────────────────────────────┬───────────────────────────────
Area │What changed │Commit
─────────────────────┼────────────────────────────────────────────────────────────────────────────────────────────────────┼───────────────────────────────
Unified runner page │Retitled, moved below the command pages it unifies, and given a nubr chip in the sidebar │ba9c84f59a
─────────────────────┼────────────────────────────────────────────────────────────────────────────────────────────────────┼───────────────────────────────
Compiling executables│The nodeExecutable examples show an absolute path alongside the $(...) form, with the Windows │b3b5052c2b, 0d9d201bf5
│spelling │
─────────────────────┴────────────────────────────────────────────────────────────────────────────────────────────────────┴───────────────────────────────
Release tooling
- The version commit now carries crates/nub-phantom/Cargo.lock. That workspace is excluded from the root and is checked with --locked in CI, so omitting it tagged a stale tree (9fdd379ba7).
What's Changed
- pm: run Windows dependency lifecycle scripts through the bundled busybox sh by @colinhacks in #940
- run: rename the standalone loader to @nubjs/runner and give it a nubr command by @colinhacks in #840 |
| 0.9.1 | 12 de setembre del 2026 | — | 64 bits ZIPARM64 ZIP Notes de la versióNub now sizes libuv's threadpool to the cores of the machine on every augmented run, takes a prefix command in nub.jsonc, runs npm ci and npm install on its own engine behind an opt-in shim, and accepts more of the npm lockfiles and projects that npm ci accepts.
Important
Augmented runs on a machine with more than four cores now get a larger libuv threadpool. Nub sets UV_THREADPOOL_SIZE to the larger of four and the cores available to the process (a container gets its cgroup quota; Windows stops at eight). On Linux the threads beyond Node's four run at nice 10, so they yield under contention. Child processes start with Node's default of four. A UV_THREADPOOL_SIZE you set yourself is used as is, and --node / NODE_COMPAT keep Node's default. See Threadpool.
Runtime
Threadpool sized to the machine
Node hands async fs, dns.lookup, async zlib and crypto calls, and native addons such as bcrypt and sharp, to a pool of four threads whatever the core count. Nub now sets the size when it starts Node, on every launcher: the file run, nub run, nubx, nub watch and lifecycle scripts.
nub server.ts # pool sized to the cores, 16 on a 16-vCPU box
node server.ts # pool of 4
UV_THREADPOOL_SIZE=6 nub server.ts # your value, used as is
The preload removes Nub's own value from process.env once the pool exists, so a cluster worker or child_process spawn gets Node's default; a child that runs through nub is sized again. On Linux the threads beyond four are reniced to 10 after the pool is built, and on the compat tier (Node 18.19–22.14) a --require sidecar builds the pool so the demoted set is exact. A bcrypt route on a 16-vCPU box went from 18 to 66 requests per second under autocannon at 64 connections, mean of three rounds (benchmark); routes that use the pool lightly are within noise of plain Node. The Threadpool page documents the behavior. (#919)
A prefix command in nub.jsonc
A project can put a command in front of everything Nub runs for it: a file run, a package.json script, and nub watch.
{
"prefix": "dotenvx run --" // split like a shell; the array form takes exact arguments
}
A script is wrapped as a whole, so a script that starts no Node process still runs behind the prefix. The program resolves from the project's node_modules/.bin chain, then PATH; a path form anchors to the file that set it. A nested nub run, or a wrapper written in Node, does not wrap the same project again. The nubx, nub dlx and node shim entrypoints do not take it, and compat mode runs without it. The field is in the config reference and the JSON schema. (#915)
AsyncContextFrame on Node 22.9–23.x
Nub passes --experimental-async-context-frame on Node 22.9 through 23.x, the band where the flag exists and does not throw. Node 24 made that AsyncLocalStorage implementation the default; on the 22 line it roughly halves the cost of carrying a store across await, which tracing SDKs and request-context plugins pay on every request. (#912)
Memory-constrained launches
On Linux x64, a direct Node launch inside a cgroup memory budget starts the main isolate with a 16 MiB V8 semi-space on two measured releases: Node 22.23.2 in a 512 MiB–1 GiB budget and Node 24.20.0 at 512 MiB. The flag is hidden from process.execArgv, Workers keep their own resourceLimits, and the tuning stands down when Node options, preloads, NODE_OPTIONS, PnP, a prefix, or an environment loader own startup. Other releases, larger budgets, budgets below 512 MiB, watch mode, and compiled executables keep Node's defaults. (#917)
User loader hooks layered above Nub's
Running tsx script.ts under nub run, or a prepare script that does, failed with require is not defined in ES module scope. Nub's load results now carry responseURL, both tiers step aside when an outer resolve hook labels a .ts file with a bare commonjs/module format, and a require.extensions handler that is already registered stays in charge of its extension. (#920)
Package manager
npm installs on Nub's engine
One opt-in routes the two npm verbs |
| 0.9.0 | 7 de setembre del 2026 | — | 64 bits ZIPARM64 ZIP Notes de la versióNub now applies a packageExtensions compatibility database to every install, repairing packages whose published code imports dependencies their own manifest never declares.
Important
Two package.json root fields changed, and one of them now errors. The top-level build allowlist is renamed allowBuilds → allowScripts, matching the map npm 12 reads from the same slot (npm/rfcs#868); a project still carrying a top-level allowBuilds is refused with ERR_NUB_ALLOW_BUILDS_RENAMED rather than warned, because honoring neither key would silently drop the map's explicit false denials. pnpm's own allowBuilds in pnpm-workspace.yaml or under package.json#pnpm is untouched. Separately, auditConfig, allowUnusedPatches and allowNonAppliedPatches are no longer read from the package.json root — no package manager reads any of the three there, and nub audit --ignore <id> already covers the audit case.
Dependency compatibility database
A package whose published code imports something its manifest never declares resolves under npm's flat node_modules — the upward directory walk finds a copy something else installed — and fails under an isolated layout. packageExtensions repairs the manifest at resolve time.
──────────────────────────┬───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┬─────────
Change │What it does │PR
──────────────────────────┼───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼─────────
Ecosystem catalogs applied│The vendored Yarn database plus pnpm's additions, 161 entries, were gated on the embedder being standalone aube, so Nub applied none of them. nub install && node -e 'require("reactcss")' failed with Cannot find module 'react'; it now resolves. │#905
──────────────────────────┼───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼─────────
Derived database bundled │Adds the machine-derived database published as @nubjs/extensions, produced by running Nub's phantom detector over the 10,000 most-downloaded packages. It is a strict superset of Yarn's. Of the 654 entries Yarn lacks, 25 add a hard dependencies edge and the rest are optional peers that install nothing and only repair strict │#907
│layouts. │
──────────────────────────┼───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼─────────
Lockfile reuse on drift │A packageExtensions edit discarded the lockfile but still handed the old graph to the resolver as a reuse hint, so the edit rewrote the checksum, installed nothing and reported "Already up to date". The hint is now withheld on real drift. │#906
──────────────────────────┴───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┴─────────
Both layer |
| 0.8.3 | 3 de setembre del 2026 | — | 64 bits ZIPARM64 ZIP Notes de la versióWhat's Changed
- compile: close the shim-capability gap at both ends, and gate it on every host by @colinhacks in #829
- docs(readme): update Homebrew installation to use core formula instead of tap by @fraluc06 in #821
- launcher: pin the probe directory's mode instead of taking it from the umask by @colinhacks in #839
- runtime cache: report why a base was refused instead of naming a cause by @colinhacks in #843
- ci: accept the dependency-axis flags pnpm's ci inherits by @colinhacks in #838
- config: only write a key that something reads back by @colinhacks in #833
- spawn: stop folding nub's own preload into the preload chainer by @colinhacks in #834
- config: refuse an .npmrc write that nub.jsonc already answers by @colinhacks in #842
- fix(config): inject the Windows local-app-data root into pnpm's config-dir resolver by @colinhacks in #831
- install: retry dependency builds a previous install could not run by @colinhacks in #836
- feat(config): a nodeExecutable field with command substitution by @colinhacks in #835
New Contributors
- @fraluc06 made their first contribution in #821
What's Changed
- compile: close the shim-capability gap at both ends, and gate it on every host by @colinhacks in #829
- docs(readme): update Homebrew installation to use core formula instead of tap by @fraluc06 in #821
- launcher: pin the probe directory's mode instead of taking it from the umask by @colinhacks in #839
- runtime cache: report why a base was refused instead of naming a cause by @colinhacks in #843
- ci: accept the dependency-axis flags pnpm's ci inherits by @colinhacks in #838
- config: only write a key that something reads back by @colinhacks in #833
- spawn: stop folding nub's own preload into the preload chainer by @colinhacks in #834
- config: refuse an .npmrc write that nub.jsonc already answers by @colinhacks in #842
- fix(config): inject the Windows local-app-data root into pnpm's config-dir resolver by @colinhacks in #831
- install: retry dependency builds a previous install could not run by @colinhacks in #836
- feat(config): a nodeExecutable field with command substitution by @colinhacks in #835
New Contributors
- @fraluc06 made their first contribution in #821 |
| 0.7.5 | 9 d’agost del 2026 | — | 64 bits ZIPARM64 ZIP Notes de la versióA memory-retention release, plus two fixes to nub upgrade.
Memory retention
Seven unbounded-retention defects, each reproduced with a fixture against a plain Node control before and after the fix. (#702)
─────────────────────┬─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┬──────────────────────────────────────────────────────────
Area │What changed │Measured
─────────────────────┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼──────────────────────────────────────────────────────────
nub run -r supervisor│Streaming mode no longer retains every prefixed output line for the child's whole life. A script that never exits — nub run -r dev — grew the supervisor 1:1 with child output. │45 → 325 MB over 50 s, now flat at 15 MB
─────────────────────┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼──────────────────────────────────────────────────────────
Aggregate output │Flushes past 8 MiB instead of buffering the entire run. A non-TTY stdout selects this path, so CI and piped runs were affected too. │250 MB climbing → flat 29 MB, output still in order
─────────────────────┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼──────────────────────────────────────────────────────────
URL.createObjectURL │Captures one compact Buffer when the Blob is built, capped at 4 MiB, and decodes only when a Worker asks for the source. │20k object URLs: +43.1 → +5.6 MB (plain Node: +1.1)
─────────────────────┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼──────────────────────────────────────────────────────────
Blob │A Blob no longer pins whatever its construction parts referenced. │2000 Blobs holding 64 KB between them: 504 → 4 MB external
─────────────────────┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼──────────────────────────────────────────────────────────
Transpile-cache sweep│Was armed on an unref'd setImmediate the process exited before running, so a user whose runs are all synchronous never swept. It is now scheduled only when a sweep is due, and │—
│ref'd. │
─────────────────────┴─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┴──────────────────────────────────────────────────────────
Upgrade
Fixes in #705.
- On Windows the command reported its install path in the extended-length form — installed v0.7.4 to \\?\C:\Users\you\.nub. The install itself was always correct. Paths are now spelled for display at the print sites, while the path used for the file swap keeps the MAX_PATH exemption a deep install directory depends on. (#704)
- A nub upgrade with nothing newer to install downloaded and swapped in the release it was already running. It now reports already on the latest release and stops. An explicit --version still reinstalls, which is what repairs a damaged install, and --stable from a canary build still downloads, because that is a channel switch. (#664)
- The upgrade line now names the version being left as well as the one arriving.
- The --yes flag advertised a confirmation prompt that has never existed. Its help text now says what it does.
Docs
The reference pages were rewritten for density — the config |
| 0.7.4 | 8 d’agost del 2026 | — | 64 bits ZIPARM64 ZIP Notes de la versióNub 0.7.4 adds guided config setup and makes missing-package errors authoritative during installs.
Configuration
nub config init creates a commented, behavior-neutral nub.jsonc at the project root. nub config init --global creates the user config instead, and both forms refuse to replace an existing file.
The config command now uses project scope by default, --global for user scope, and nub global config as the prefix form. The former --location option has been removed. Protected npm credentials continue to default to the user .npmrc; --local selects a project credential explicitly. (#694)
Package installation
Missing registry packages now fail with ERR_NUB_PACKAGE_NOT_FOUND before similarity or package-age warnings run. Public unscoped typos can include a non-interactive suggestion; scoped package names no longer suggest unrelated basenames from another namespace. (#693)
Documentation and site
─────────────────┬──────────────────────────────────────────────────────────────────────────┬────────────
Area │What changed │Commit
─────────────────┼──────────────────────────────────────────────────────────────────────────┼────────────
Release archive │Added the Nub 0.7.3 release post │5b690fb
─────────────────┼──────────────────────────────────────────────────────────────────────────┼────────────
Blog structure │Reorganized the Nub 0.7.0 post and extracted the reusable Nub introduction│9888c8a
─────────────────┼──────────────────────────────────────────────────────────────────────────┼────────────
Table of contents│Kept identifiers together when sidebar entries wrap │a825d75
─────────────────┼──────────────────────────────────────────────────────────────────────────┼────────────
Config copy │Tightened the config docs and Nub introduction │55b6294
─────────────────┴──────────────────────────────────────────────────────────────────────────┴────────────
What's Changed
- fix(add): report missing packages before reputation warnings by @colinhacks in #693
- config: add init and global scope grammar by @colinhacks in #694 |
| 0.7.3 | 8 d’agost del 2026 | — | 64 bits ZIPARM64 ZIP Notes de la versióA Windows fix for nub run, native TypeScript transform configuration, and import-text on the Node 24 LTS backport.
Important
Windows npm installs could not run scripts. On 0.7.0–0.7.2, nub run failed on Windows with "bundled POSIX shell (busybox.exe) was not found" from the second invocation onward. Upgrading fixes it; there is nothing to clean up by hand.
Windows
nub run executes script bodies through a bundled busybox sh, which the binary resolves relative to itself. 0.7.0 began hardlinking nub.exe into npm's global bin directory for a faster dispatch path, which moved the binary away from that shell — so the first call after an install worked and every later one failed. The launcher now carries the shell into a nub-sh/ subdirectory beside the relocated binary, and the resolution accepts that layout. It goes in a subdirectory rather than beside the executable because that directory is on PATH, where a bare busybox.exe would shadow a busybox the user installed themselves. (#699, #687)
Configuration
Project nub.jsonc gains six native TypeScript transform fields — jsx, jsxFactory, jsxFragmentFactory, jsxImportSource, decorators, and emitDecoratorMetadata. (#697)
Runtime
───────────┬──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┬────────────
Area │What changed │Commit
───────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼────────────
import-text│--experimental-import-text is injected on the 24.19.0 LTS backport band as well as 26.5+, so a Node that knows the flag no longer falls through to the default loader and fails with │439853b
│ERR_UNKNOWN_FILE_EXTENSION │
───────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼────────────
TypeScript │customConditions from tsconfig.json are applied as Node export conditions │005e8e4
───────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼────────────
Environment│An explicit env file is refused when Varlock owns the environment, rather than being silently layered │dfe9b73
───────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼────────────
Environment│.env.schema ownership is decided by loader resolution, and a missing schema is a refusal rather than a degrade │7dfeb95
───────────┴──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┴────────────
Types
@nubjs/types splits its shared declarations into common.d.ts and routes pre-6.0 compilers through a dedicated entry, so proposal declarations coexist with the official ones as they land. The fixture matrix runs under TypeScript 5.9, 6.0 and 7.0. (e29dc5c)
Testing & internals
- The Windows busybox probe runs its whole case matrix against both shell layouts, plus a negative control that fails when no shell is present (#699).
- A stray root nub.jsonc setting nodeCompat: true was removed; it disabled augmentation for every in-tree test and took the whole test matrix red (#696, #695).
- The v0.7 config-schema snapshot was refreshed against latest.json after the transform fields landed, restoring the release verification gate (f58f09f).
- Documentation for the runtime API augmentations, Varlock, |
| 0.7.2 | 7 d’agost del 2026 | — | 64 bits ZIPARM64 ZIP Notes de la versióSupply-chain and workspace resolution fixes, plus per-invocation platform selection for cross-platform installs.
Release-age gate
Running a tool without naming a version resolves the latest tag, which narrowed to that one version — so a minimumReleaseAge window covering it left nothing to fall back to and nubx <tool> failed outright. A blocked latest now resolves to the newest release that clears the window (#682, #681).
$ nubx some-tool
+ some-tool@2.3.0 latest 2.4.0
warn: the latest some-tool release (2.4.0) is younger than minimumReleaseAge; using 2.3.0 instead
help: to take the newest release anyway: `--minimum-release-age=0`, or `--minimum-release-age-exclude=some-tool`
The fallback stops at whatever the publisher currently tags latest, so a higher version they published and then untagged is never selected, and a latest pointing at a prerelease is refused rather than falling back onto a stable release from an older line. The same narrowing also affected the non-strict mode in the opposite direction — the blocked release was the only candidate, so it was re-selected and the window had no effect. It is now enforced there too.
Installs
──────────────────┬──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┬────────────
Area │What changed │Commit
──────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼────────────
Platform selection│--os, --cpu and --libc select optional dependencies for a target other than the host, per invocation (#683) │af33650
──────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼────────────
Workspace protocol│A workspace:<path> tail naming a member directory resolves to that member instead of being read as a version range and sent to the registry (#674) │ab7350e
──────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼────────────
Prewarm │The prewarm graph is host-filtered under the isolated layout, matching the linked tree (#679) │adac3af
──────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼────────────
Patch application │A failing hunk reports its number and line, counted from 1, with what was searched for and that the patch needs regenerating (#674) │ab7350e
──────────────────┴──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┴────────────
Diagnostics
The refusal to accept a nodeOptions entry now names NODE_OPTIONS as the constraint doing the refusing (#684, c178118).
Documentation
The package-manager page's layout section is reworked to state the policy as neutral-surface-first, with a dead npmrc example corrected and a duplicated build-approval enumeration removed.
What's Changed
- fix: name NODE_OPTIONS as the constraint refusing a nodeOptions entry by @colinhacks in #684
- fix(install): host-filter the prewarm graph under the isolated layout too by @colinhacks in #679
- feat(install): --os / --cpu / --libc for per-invocation platform selection by @colinhacks in #683
- fix(aube): resolve workspace: specifiers, and say where a patch hunk failed by @colinhacks in #674
- fix(resolver): fall back to the newest mature release when the age gate blocks latest by @colinhacks in #682 |
| 0.7.1 | 5 d’agost del 2026 | — | 64 bits ZIPARM64 ZIP Notes de la versióInstallation fixes: Homebrew works again, and reinstalling no longer leaves the package-manager shims on the previous binary.
Important
Homebrew could not install nub 0.7.0. Both brew install nubjs/tap/nub and brew upgrade failed with Errno::ENOENT: No such file or directory - bin/nubx, on macOS and Linux alike. Run brew update && brew upgrade nub to pick up the fix.
Installation
Release archives have shipped a single binary since 0.7.0, with the nub and nubx verbs selected from the argv[0] basename. Each installer creates the nubx alias itself — the Homebrew formula was the one that had not been updated to do so.
───────────────────────┬─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┬─────────
Area │What changed │Ref
───────────────────────┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼─────────
Homebrew │The formula installs bin/nub and creates nubx as a symlink beside it, and its test asserts that the alias dispatches rather than merely existing. │#676
───────────────────────┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼─────────
Curl and irm installers│Reinstalling now refreshes the ~/.nub/shims hardlinks. Those point at the nub binary, so replacing it left npm, npx, pnpm, pnpx, yarn and yarnpkg running the previous version with no error and no │#678
│warning. │
───────────────────────┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼─────────
Windows self-update │The upgrade carries busybox.exe across. Upgrading from a release older than 0.6.0 left nub run unable to find nub's bundled shell, with no fallback. │#678
───────────────────────┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼─────────
Release pipeline │The generated Homebrew formula is installed and tested on macOS before it is pushed to the tap, so a formula that cannot install no longer reaches users. │#678
───────────────────────┴─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┴─────────
Runtime
An inherited NODE_OPTIONS preload no longer displaces nub's own. A consumer that re-parses NODE_OPTIONS keeps one value per flag name, and nub appended the inherited value last — so the token dropped was nub's preload, and the augmentation layer went with it. That is the shape an APM injector uses, so an application running under an agent lost augmentation silently. Inherited --require and --import values are now folded into the same chainers as the configured ones. (#675)
Testing and internals
────────────────────┬────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┬────────────
Area │What changed │Commit
────────────────────┼────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼────────────
Installer harness │Covers reinstalling over an existing install. Every case before it installed into an empty sandbox, which is why the shim staleness went unseen.│7ae0514
────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── |
| 0.7.0 | 5 d’agost del 2026 | — | 64 bits ZIPARM64 ZIP Notes de la versióNub 0.7.0 adds nub.jsonc, a typed configuration file for the runtime, installs, and temporary package runs; hands environment loading to Varlock when a project has an @env-spec schema; and fixes a hoisted-linker defect that deleted build output.
Important
Five changes affect existing projects on upgrade.
- Adding a package now challenges unfamiliar names. A public npm name first registered in the last 30 days prompts in a terminal and fails without one, and a name closely resembling a popular package is challenged the same way. Both gates are new in this release. Lockfile entries are exempt; pass --allow-low-downloads for one invocation, or set minimumPackageAge=0 in .npmrc.
- The release-age gate now fails closed. A registry that serves no publish times silently disabled the 24-hour cooling window, including under the default minimumReleaseAgeStrict=true. Nub now falls back to the package's last-modified time, and refuses when even that cannot establish an age — so a registry without publish metadata will block where it previously installed. Ways through: minimumReleaseAgeExclude, minimumReleaseAge=0, or the new per-invocation flag.
- The allowBuilds field is no longer read from .npmrc. Set it in pnpm-workspace.yaml or package.json instead. A project that kept its build allowlist in .npmrc will see those dependencies need approval again.
- A bunfig.toml [install].linker value is no longer read. Nub cannot reproduce Bun's linker modes from that setting, so a Bun-owned project gets Nub's default layout. Choose one explicitly with install.linker in nub.jsonc or node-linker in .npmrc. Yarn's nodeLinker is unaffected.
- Scripts now receive the node-options field from .npmrc, matching npm and pnpm. A project that set it for other tools will see those options reach its scripts for the first time.
The first install after upgrading re-bootstraps two caches once, because their on-disk paths were renamed. Nothing is re-downloaded.
Project configuration
A project can now carry a nub.jsonc at its root — one typed file for the runtime, installs, and dlx, in JSON with comments and trailing commas. Nub finds the nearest one by walking up from the working directory.
{
"$schema": "https://nubjs.com/schema/latest.json",
"preload": ["./instrumentation.ts"],
"conditions": ["development"],
"loader": { ".graphql": "text" },
"install": {
"linker": { "strategy": "global-virtual-store", "eject": ["electron"] },
"minimumReleaseAge": "3d"
}
}
Settings resolve most-specific-first: a command-line option, then an environment variable, then the project file, then a global ~/.config/nub/nub.jsonc, then the built-in default. The two files take the same fields and are validated differently on purpose — the project file is checked in and shared, so an unknown key stops the command; the global file applies to every project on your machine, so an unrecognized section is ignored rather than taking the rest of your defaults down with it.
Read and write any field with nub config, which validates against the same rules that read the file and rewrites it in place. Comments, blank lines, and key order survive an edit. Keys that are not fields of this file keep their existing meaning and still read and write .npmrc.
nub config set install.linker hoisted
nub config set preload '["./setup.ts"]'
nub config set --location user envFile false # personal default, everywhere
nub config path
The full field list is in the config reference. A JSON Schema ships at https://nubjs.com/schema/latest.json for editor completion. (#587)
Schema-driven environments
An @env-spec schema — conventionally .env.schema — describes an environment as types, validation, which variables are secret, and where their values come from. Varlock implements that format. Install it, and Nub hands the environment over rather than loading .env* itself.
nub add -D varlock
nub server.ts
Nub does not resolve the schema, inject values, or redact anything. It runs Varlock in front of Node, so type generation, prov |
| 0.6.0 | 25 de juliol del 2026 | — | 64 bits ZIPARM64 ZIP Notes de la versióNub 0.6.0 runs every package.json script body through a POSIX shell on all three platforms, makes the 24-hour install trust floor fail closed, and adds a canary release channel.
Important
Two changes affect existing projects on upgrade.
Windows script bodies now run under a POSIX shell instead of cmd.exe. A script written in cmd syntax — set NODE_ENV=production && node build.js, rd /s /q dist, %VAR% — no longer works. Rewrite it in POSIX syntax (which then works on every platform), or opt back out with script-shell=cmd in .npmrc or --script-shell cmd.
The minimumReleaseAge cooling window now fails closed. When every version satisfying a range was published less than 24 hours ago, the install errors instead of falling back to the lowest satisfying version. Set minimumReleaseAgeStrict=false in .npmrc to restore the previous fallback.
The first install after upgrading also re-links node_modules once and rebuilds native addons once, because the install caches are now keyed on the Node engine. Nothing is re-downloaded.
Script bodies run through a POSIX shell
One script body now behaves the same on macOS, Linux, and Windows — &&, pipes, $(…), ${PORT:-3000}, and globs included. macOS and Linux use the system /bin/sh. Windows has no POSIX shell, so Nub ships busybox next to its binary and uses it by default in place of cmd.exe; this adds about 700 KB to the Windows artifacts only.
Extra arguments are now escaped for the target shell and spliced onto the unescaped script body, matching how npm does it, so a multi-word argument reaches the script as a single token while the body's own expansions still run. (#559, closes #399)
The install trust floor fails closed
Nub pins both halves of the release-age floor at its own tier: a 24-hour window, and a hard failure when no version in range is old enough. The documented posture was already a hard gate; the implementation now matches it. Explicit user configuration still overrides both — the values are defaults, not policy. (#544)
Canary channel
Every code push to main now publishes a full 8-platform build under a rolling canary release and the npm canary dist-tag.
curl -fsSL https://nubjs.com/install.sh | bash -s canary # macOS, Linux
npm install -g --ignore-scripts=false @nubjs/nub@canary
A script install switches channels in place with nub upgrade --canary; nub upgrade --stable returns to the latest stable release. On a canary build, a plain nub upgrade stays on canary. (#551, #557, #558)
Interactive update picker
nub update -i replaces the pre-selected multiselect with a per-row keep-or-update table. Pressing enter with nothing selected now updates nothing rather than everything, and -i --latest folds into the same picker. Non-interactive nub update is unchanged. Minor-version rows in nub outdated moved from cyan to yellow. (#512, closes #483)
Package manager fixes
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┬─────────────────────────────────────────────────
Fix │PR
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼─────────────────────────────────────────────────
Install caches — global virtual store, side-effects cache, freshness and delta gates — are keyed on the project's Node engine, so switching Node versions no longer reuses artifacts built for another one. Dependency build scripts in a workspace member now anchor to the workspace root, matching npm and pnpm.│#530, #537, #538, #542, #548
───────────────────────────────────────────────────────────────────────────────── |
| 0.5.0 | 22 de juliol del 2026 | — | 64 bits ZIPARM64 ZIP Notes de la versióWhat's Changed
- fix(publish): preserve scope in publish attachment key and tarball URI by @pullfrog[bot] in #478
- Fall back to webpki roots and system DNS on Android (no-JVM builds) by @colinhacks in #501
- feat(init): ship nub init — TypeScript-first project scaffold by @colinhacks in #499
- upgrade: support the self-owned channel on Windows by @colinhacks in #506
- pm: run approved build scripts during approve-builds by @colinhacks in #503
- fix(spawn): macOS group-reaper watcher so SIGKILL of the nub process group can't orphan the workload by @colinhacks in #504
- pm: exclude workspace link packages from dedupe diff by @colinhacks in #502
- fix(pm): clamp identity walk-up to nub's cache root for internal scratch installs by @colinhacks in #513
- fix(pm): cache dist-tag resolution and slim registry metadata fetches by @colinhacks in #505
- node install: stream extraction during download, overlap checksum fetch by @colinhacks in #508
- linker: workspace-spanning hoisted planning for nodeLinker=hoisted by @colinhacks in #511
- feat(pm): sanction top-level packageExtensions under nub identity by @colinhacks in #507
- fix(pm): enforce + role-scope packageExtensions under nub identity by @colinhacks in #509
- pm: accept dist-tag specs in update args by @colinhacks in #516
- chore: remove dead code and tighten visibility via cargo-hawk by @colinhacks in #514
- fix(watch): forward explicit --env-file to the watched Node so restarts re-read it by @colinhacks in #510
- fix(spawn): dispatch the parent-death watcher verb above argv0 detection by @colinhacks in #517
- aube: sync vendored engine to upstream v1.32.0 by @colinhacks in #519
- revert(nubx): drop the unified file/script tiers, back to npx parity by @colinhacks in #525
- init: scaffold typescript ^7 as a devDependency by @colinhacks in #526
- fix(pm): export npm_config_user_agent to dlx/create/exec children by @colinhacks in #529 |
| 0.4.13 | 15 de juliol del 2026 | — | 64 bits ZIPARM64 ZIP Notes de la versióA Windows-only fix for where the global content-addressable store is placed.
Important
On Windows, a machine that already ran nub has a stale store at %USERPROFILE%\.local\share
ub\store. After upgrading, the next install re-populates the store under %LOCALAPPDATA% — a one-time re-download, no breakage. The old .local\share
ub directory can be deleted. macOS and Linux are unaffected.
Package manager
On Windows, nub store path reported the content-addressable store under a Unix-style .local\share path (C:\Users\<user>\.local\share
ub\store\v1) instead of %LOCALAPPDATA%
ub\store, splitting the CAS store from the cache and virtual-store tiers that already sat under %LOCALAPPDATA%. The data-dir resolver now has a %LOCALAPPDATA% branch, so the Windows data root resolves to %LOCALAPPDATA%
ub, matching the cache tier and Node's platform conventions. Unix and macOS behavior is unchanged. (#476, closes #451)
What's Changed
- fix(pm): resolve the global store dir under %LOCALAPPDATA% on Windows by @colinhacks in #476 |
| 0.4.12 | 15 de juliol del 2026 | — | 64 bits ZIPARM64 ZIP Notes de la versióThis release fixes a batch of package-manager and runtime issues — most of them around the global virtual store — and adds Node version resolution from .tool-versions.
Package manager
────────────────────┬────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┬─────────
Area │What changed │PR
────────────────────┼────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼─────────
Global virtual store│Trusted packages whose build script targets the consuming project — git-hook installers such as simple-git-hooks, and similar — are now ejected from the shared store and built project-local, so their postinstall runs against your project instead of failing in the │#475
│store │
────────────────────┼────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼─────────
Global virtual store│Type-only phantom dependencies in .d.ts and Vue SFC type surfaces are now detected │#452
────────────────────┼────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼─────────
Lockfile import │Importing a bun or npm lockfile to pnpm-lock now runs the peer-context pass │#471
────────────────────┼────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼─────────
Version cache │Incomplete version-cache entries are repaired instead of erroring │#467
────────────────────┼────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼─────────
Yarn Berry │Frozen-install drift validation fixed for workspaces │#462
────────────────────┴────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┴─────────
Runtime
- Async hook tier is auto-selected when a foreign loader is detected in the preload (#472).
- Web Locks dictionary conversion aligned to the spec (#461).
Node version management
- Node version resolution now reads asdf/mise .tool-versions (#474).
- Temporary PATH shim directories are hardened (#470).
Process and watch
- nub run arms PR_SET_PDEATHSIG on the script child, so a SIGKILL on the leader can no longer orphan the workload (#464).
- Runtime env keys are filtered across nub watch restarts (#466).
Installer
- The install script verifies release-archive checksums (#459).
Build and internals
- Rust floors raised (workspace 1.93, nub-native 1.95); a local verification target added; a redundant phantom sidecar backfill removed.
Documentation
- A new Deployment section (hosted builds, setup-nub, Docker), a Nub vs Vite+ comparison guide, and corrected runtime and Yarn PnP claims.
What's Changed
- docs: correct ShadowRealm and Yarn PnP claims by @colinhacks in #456
- build: set Rust 1.93 floor by @ |
| 0.4.11 | 12 de juliol del 2026 | — | 64 bits ZIPARM64 ZIP Notes de la versióWhat's Changed
- feat(installer) supports basic setup customization by @daniele-orlando in #420
New Contributors
- @daniele-orlando made their first contribution in #420 |
| 0.4.10 | 12 de juliol del 2026 | — | 64 bits ZIPARM64 ZIP Notes de la versióTwo package-manager install fixes.
Package manager
──────────┬─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┬─────────
Area │What changed │PR
──────────┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼─────────
Expo │A project on Expo below SDK 56 now installs with a project-local virtual store instead of the shared global store. Metro before SDK 56 resolves modules by real path and can't reach the machine-global store; Expo 56+ (its On-demand Filesystem) is store-aware and keeps the shared store.│#446
──────────┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼─────────
Workspaces│A newly-added workspace member now resolves against the shared lockfile layout instead of failing to link. │#443
──────────┴─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┴─────────
What's Changed
- fix(install): resolve a newly-added workspace member on the shared lockfile layout by @colinhacks in #443
- feat(pm): version-gate the Expo GVS eject on SDK 56 by @colinhacks in #446 |
| 0.4.9 | 12 de juliol del 2026 | — | 64 bits ZIPARM64 ZIP Notes de la versióAdds pnpm named-registry support, so dependencies that resolve through a registry alias install under nub.
Named registries
When pnpm is the incumbent package manager, nub now honors pnpm's namedRegistries — an alias-to-registry-URL map declared in pnpm-workspace.yaml or the global pnpm config.yaml. A dependency spec prefixed with the alias resolves from that registry:
# pnpm-workspace.yaml
namedRegistries:
work: https://npm.example.com/
// package.json
{ "dependencies": { "@work/constants": "work:1.x.x" } }
Both direct and transitive named-registry specs resolve. The built-in gh: alias points at GitHub Packages (https://npm.pkg.github.com/), and a user entry can repoint it at a GitHub Enterprise host. Authentication is read from existing per-URL .npmrc entries — //host/:_authToken=… — so no new auth configuration is needed. (#444, #440)
Before this, a named-registry spec fell through to the default registry and failed to resolve (no version of @work/constants matches range work:1.x.x).
What's Changed
- feat(resolver): support pnpm namedRegistries in pnpm-compat mode by @colinhacks in #444 |
| 0.4.8 | 11 de juliol del 2026 | — | 64 bits ZIPARM64 ZIP Notes de la versióA lockfile-compatibility fix plus documentation updates.
Lockfile compatibility
nub install failed with ERR_NUB_MANIFEST_PARSE ("invalid type: map, expected a string") on a valid pnpm-lock.yaml when a package's engines: field held a nested map instead of a string range. Some legacy packages (e.g. cordova-plugin-inappbrowser) put a nested cordovaDependencies map under engines, which pnpm preserves verbatim in the lockfile. Nub's lockfile parser now tolerates non-string engines values — keeping the string ranges and ignoring the nested extras — matching how it already parses package.json. (#439, fixes #417)
Documentation
────────────────┬────────────────────────────────────────────────┬────────────
Area │What changed │Commit
────────────────┼────────────────────────────────────────────────┼────────────
Vite+ comparison│New "Nub vs Vite+" comparison guide │b5bae7f
────────────────┼────────────────────────────────────────────────┼────────────
Vite+ comparison│Table updated with per-tool attributions │7dfbe01
────────────────┼────────────────────────────────────────────────┼────────────
Vite+ comparison│Package-manager shims marked partial (npm only) │6a310f0
────────────────┼────────────────────────────────────────────────┼────────────
Vite+ comparison│Expanded prose on runtime augmentation and scope│6e31cf6
────────────────┼────────────────────────────────────────────────┼────────────
Vite+ comparison│Runtime-augmentation feature list added │8cfba4f
────────────────┼────────────────────────────────────────────────┼────────────
Bun-to-nub guide│Recommend DX-mirroring, trusted alternatives │4478fbb
────────────────┼────────────────────────────────────────────────┼────────────
Docs sidebar │Separators render as visible rules │e384f8f
────────────────┴────────────────────────────────────────────────┴────────────
What's Changed
- fix(lockfile): tolerate nested-map engines values in pnpm-lock.yaml by @colinhacks in #439 |
| 0.4.7 | 10 de juliol del 2026 | — | 64 bits ZIPARM64 ZIP Notes de la versióA fix for dependencies whose install scripts replace a JavaScript launcher with a native binary — most visibly esbuild.
Native-executable bins
A package's bin can start as a JavaScript launcher and be swapped for a platform-native executable by its install script — esbuild does exactly this. nub linked the node_modules/.bin entry before the install script ran, so the shim invoked the binary as node <binary> and failed with a syntax error (nubx esbuild, ./node_modules/.bin/esbuild, and any script calling esbuild).
nub now detects native executables (ELF, Mach-O, PE) and runs them directly — a symlink on Unix, a direct-exec wrapper on Windows — instead of wrapping them in node. Bin shims are also regenerated after dependency install scripts run, so a launcher that turns native mid-install gets the correct shim, including on the side-effects-cache restore path. (#412, fixes #394)
What's Changed
- fix(linker): exec native-executable bins directly instead of wrapping in node by @colinhacks in #412 |
| 0.1.0 | 17 de juny del 2026 | — | 64 bits ZIPARM64 ZIP |