Package meta-manager
Provision and run the package manager your project pins — corepack's job, in native Rust. The exact pnpm, npm, or yarn release is fetched, verified, cached, and run on the project's Node.
Nub reads your project's package-manager pin, fetches that exact version from the npm registry — integrity-verified, cached under ~/.cache/nub/pm — and runs it under the project's Node. No corepack, no enable step, no baked version table: a six-month-old Nub binary provisions today's pnpm.
$ nub pm which
/Users/you/.cache/nub/pm/pnpm/9.15.4/package/bin/pnpm.cjs
» resolved from packageManager (pnpm@9.15.4)Pin resolution
The pin is read from two package.json fields at the workspace root, in order:
packageManager— the corepack field. Exact only (pnpm@9.15.4, optionally+sha512.<hash>).devEngines.packageManager—{ name, version }; the version may be a range.
Ranges belong in devEngines; corepack, pnpm, and Yarn all reject them in packageManager. With no pin in either field, nub pm which errors and points at nub pm use. A lockfile never implies a pin.
Multiple lockfiles
Two PMs' lockfiles side by side (pnpm-lock.yaml and package-lock.json) is ambiguous — Nub errors (ERR_NUB_LOCKFILE_AMBIGUOUS). Remove the stale one, or declare the pin with nub pm use.
Yarn Berry
A committed Berry release (.yarnrc.yml yarnPath) wins over the pin fields above. Nub runs the committed file directly and never provisions Berry, so a yarn@2+ pin without a committed release errors. Yarn classic (1.x) provisions like any other manager.
CLI
nub pm which
Print the resolved package manager — path on stdout, provenance on stderr, so PM=$(nub pm which) captures just the path. Provisions the pinned version if it isn't cached yet.
$ nub pm which
/Users/you/.cache/nub/pm/pnpm/9.15.4/package/bin/pnpm.cjs
» resolved from packageManager (pnpm@9.15.4)nub pm use
Declare the project's package manager — npm, pnpm, Yarn, or Bun. One command resolves the version (exact, range, or dist-tag; bare means latest), fetches and verifies it, writes packageManager, and aligns the lockfile.
nub pm use pnpm # newest pnpm
nub pm use npm@10 # newest 10.x
nub pm use pnpm@9.15.4 # exactMoving an npm project to pnpm:
$ nub pm use pnpm
Fetching pnpm 11.5.3 (4 MB)...
using pnpm@11.5.3
package.json: packageManager = pnpm@11.5.3 (+sha512)
package.json: devEngines.packageManager = { name: "pnpm", version: "^11.5.3", onFail: "warn" }
pnpm-lock.yaml: written (converted from package-lock.json)
package-lock.json: removed (migrated)What it writes:
package.json#/packageManager— the exact version plus a+sha512hash from the verified tarball. What corepack, pnpm, and turbo execute;useis the only Nub command that writes it.package.json#/devEngines/packageManager—{ name, version: "^<exact>", onFail: "warn" }, the range-and-policy form npm and pnpm enforce natively, written beside the exact pin so the two can't drift.- The lockfile, in the new manager's format. A lockfile in another format is converted — resolution state preserved — and the old file removed. One already in the target format is left untouched; with no lockfile, the next install creates it. The converted lockfile passes the active manager's frozen install (
pnpm install --frozen-lockfile, etc.) byte-for-byte.
Config is not migrated
Switching managers converts the lockfile, not your config. The .npmrc, any pnpm.* fields, pnpm-workspace.yaml settings, and other manager-specific config stay as they are — Nub does not translate them. Carry over whatever the new manager needs yourself.
Every file written or removed is named in the output; rerunning is a no-op. The refusals, all before anything is written:
- Multiple foreign-format lockfiles — remove the stale ones first.
- A binary
bun.lockbsource — regenerate it as text first withbun install --save-text-lockfile. use yarnonto a Berry (2+)yarn.lock— classic would downgrade the format; useyarn set version.use yarnon a graph using theworkspace:protocol — classic yarn can't express it.
A converting use yarn is otherwise fine — Nub writes a classic yarn.lock directly. Running use bun writes the pin and lockfile but doesn't provision bun.
nub pm update
Bump the pin: resolve the newest version satisfying the devEngines range (or the registry latest if there's no range), provision it, and rewrite packageManager with a fresh hash. Alias: nub pm up.
$ nub pm update
Fetching pnpm 9.15.9 (4 MB)...
updated pnpm 9.15.4 → 9.15.9nub pm cache
Inspect or clear the package-manager cache.
$ nub pm cache
pnpm@9.15.4
yarn@1.22.22
$ nub pm cache clearVersions live at ~/.cache/nub/pm/<pm>/<version>. A cached exact pin runs fully offline — the registry is only contacted to resolve ranges and fetch missing versions. Provisioned managers run with a warm V8 compile cache (NODE_COMPILE_CACHE), so the PM's multi-megabyte bundle loads as cached bytecode instead of re-parsing on every call.
nub pm shim
The shims are an opt-in: run nub pm shim and a bare pnpm, npm, or yarn command routes through Nub to the pinned manager, with nub pm unshim to remove them. Default usage needs none of this — nub install and nub run already run the pin. See Package-manager shims for the install, the strict-by-default refusal, and the per-invocation overhead.
.npmrc
The PM download — packument and tarball — goes through your .npmrc: registry= picks the mirror, //host/:_authToken= authenticates. An auth-required Artifactory/Nexus mirror works with the config you already have:
registry=https://npm.corp.example
//npm.corp.example/:_authToken=${CORP_NPM_TOKEN}To fetch package managers from a different registry than your dependencies, COREPACK_NPM_REGISTRY (+ COREPACK_NPM_TOKEN) overrides the PM-download registry — teams migrating off corepack keep their existing CI vars.
Node managernub node
Manage the Node versions Nub provisions — pin a version and it's fetched automatically, or drive the cache explicitly with the install, list, uninstall, and pin subcommands.
Package-manager shims
An opt-in for muscle memory. Install the shims and a bare pnpm, npm, or yarn command routes through Nub to the package manager your project pins, with no extra Node process in front.