pnpm
pnpm is the package manager Nub mirrors most closely — native version-9 lockfile read and write, an isolated dependency tree, and pnpm's hook file, all gated on pnpm being the incumbent.
Nub mirrors pnpm most closely: the CLI surface, the isolated node_modules layout, and the lockfile. When pnpm is the incumbent — a packageManager: "pnpm@…" field or an existing pnpm-lock.yaml — Nub reads and writes pnpm's own pnpm-lock.yaml in its native format, and honors pnpm's config. Everything below is gated on that.
| Feature | pnpm | nub | Notes |
|---|---|---|---|
pnpm-lock.yaml | Supported | Supported | v9, read + write |
pnpm-workspace.yaml | Supported | Supported | |
.pnpmfile.cjs | Supported | Supported | |
pnpm.overrides | Supported | Supported | |
resolutions | Supported | Supported | |
allowBuilds / onlyBuiltDependencies | Supported | Supported | |
catalog: | Supported | Supported | |
workspaces | Supported | Supported | |
.npmrc | Supported | Supported |
Lockfile
Nub reads and writes pnpm lockfile v9 (lockfileVersion: '9.0') — what pnpm 9 and 10 emit. A lockfile Nub writes installs cleanly under pnpm:
$ nub install
dependencies:
+ is-odd@3.0.1
$ grep lockfileVersion pnpm-lock.yaml
lockfileVersion: '9.0'
$ pnpm install --frozen-lockfile
Lockfile is up to date, resolution step is skippedThe round-trip holds both directions, for single packages and for workspaces with catalog: and workspace: entries (verified against pnpm 10.15.1). Nub adds one thing pnpm doesn't: a time: block of per-package publish timestamps used by the resolver's release-age floor. pnpm tolerates and preserves it, so a git diff against a pnpm-written lockfile will show it.
Older formats — v6 (pnpm 8) and v5.4 (pnpm 7) — keep root dependencies under a top-level dependencies: map instead of v9's importers:, which Nub's reader doesn't understand. Rather than misread one as an empty project and link nothing, Nub refuses up front and leaves your node_modules and lockfile untouched:
# captured: nub 0.0.44 on a lockfileVersion: '6.0' lockfile
$ nub install
Error: ERR_NUB_LOCKFILE_UNSUPPORTED_FORMAT
× pnpm-lock.yaml is lockfileVersion 6.0 (pnpm 8); nub reads v9 (pnpm 9+).
help: Re-lock under pnpm 9+ (`pnpm install`), then `nub install`.The refusal names the detected version (v5.4 reads (pnpm 7)). Migrate by running a one-time pnpm install under pnpm 9+ to upgrade the lockfile to v9, then nub install.
Config
When pnpm is the incumbent, Nub honors pnpm's configuration surface:
pnpm-workspace.yaml—packages:globs and thecatalog:/catalogs:maps.pnpm.overrides— version pins applied during resolution, written into the lockfile'soverrides:block.pnpm.onlyBuiltDependencies/pnpm.neverBuiltDependencies/pnpm.allowBuilds— feed Nub's lifecycle-script policy..pnpmfile.cjs/.pnpmfile.mjs— thereadPackageandafterAllResolvedhooks run (Nub shells out to Node, so existing hooks work unchanged).
# pnpm-workspace.yaml
packages:
- 'packages/*'
catalog:
lodash.merge: 4.6.2// package.json
{
"pnpm": { "overrides": { "is-number": "7.0.0" } }
}pnpm prefers pnpm.overrides; top-level resolutions is still honored (pnpm supports it for Yarn compatibility), but top-level overrides is npm/bun's field and is ignored under pnpm.
Under a non-pnpm incumbent — npm, Yarn, Bun, or a Nub-identity project — none of this is read. For npm, Yarn, and Bun incumbents, a stray .pnpmfile.cjs is ignored with a warning rather than applied silently:
$ nub install
nub: `.pnpmfile.cjs` ignored — this project uses npm, which doesn't apply pnpmfile hooks. Remove it, name it explicitly with `--pnpmfile`, or switch to pnpm (`nub pm use pnpm`).Under Nub identity, pnpm-named files are outside the supported config surface and default .pnpmfile.cjs / .pnpmfile.mjs files are ignored silently. An explicit --pnpmfile <path> always loads.
Install behavior
The default node_modules layout is isolated — pnpm's symlink-into-a-virtual-store scheme. Nub's store is node_modules/.nub/ rather than node_modules/.pnpm/; the layouts are equivalent in shape but not byte-shared, so alternating tools relinks the tree. The --node-linker hoisted flag gives the flat npm-style layout.
There is no pnp linker. Nub rejects it rather than falling back silently:
$ nub install --node-linker pnp
× node-linker=pnp is not supported by nub; use `isolated` (default) or # ❌
│ `hoisted`Lifecycle scripts for dependencies are skipped by default, exactly as pnpm 10 does. A package runs install scripts only when allowlisted via pnpm.onlyBuiltDependencies (or pnpm.allowBuilds), or when Nub's gated default-trust floor vouches for it (see Security); nub approve-builds adds an entry interactively. pnpm.neverBuiltDependencies is a denylist that wins over any allow and over the floor.
Gaps
- Lockfile is v9-only. v6 (pnpm 8) and v5.4 (pnpm 7) are not parsed — Nub refuses with
ERR_NUB_LOCKFILE_UNSUPPORTED_FORMAT(exit 1) and leavesnode_modulesand the lockfile untouched. Re-lock with pnpm 9+ first. - No
nodeLinker: pnp. Onlyisolated(default) andhoisted;--node-linker pnperrors. - Virtual store is
node_modules/.nub/, not.pnpm/. Equivalent shape, not byte-shared; alternating tools relinks. - Config is incumbent-gated. A non-pnpm-incumbent project ignores
pnpm-workspace.yaml,pnpm.*, and.pnpmfile.cjs. Nub identity ignores default pnpmfile hooks silently; npm, Yarn, and Bun incumbents warn. - A
time:block appears in the lockfile. Per-package timestamps pnpm doesn't write; harmless and preserved, but visible in agit diff.
Package manager
Nub ships its own installer with a pnpm-shaped CLI and lockfile-compatibility with whatever your project already uses — npm, pnpm, and Bun round-trip, Yarn read-only.
npm
Nub speaks npm's on-disk formats — the version-2 and version-3 lockfile round-trips byte-for-byte, and npm config is read across npm's builtin, global, user, and project scopes. The CLI is pnpm-shaped; the files are npm's.