Notes from replacing pnpm with Nub — the all-in-one Node.js toolkit (runtime + package manager + Node version manager) — on an Apple Silicon Mac running Laravel Herd. Written June 2026, Nub v0.2.7.
- pnpm installed via Corepack is not an npm/Homebrew package — you "uninstall" it with
corepack disable pnpm, then delete its store at~/Library/pnpm. - Install Nub outside any version-managed Node (Homebrew/curl), or it ends up trapped inside a Node it's supposed to manage.
- Nub can fully replace nvm, but Laravel Herd's bundled nvm can't be cleanly uninstalled as a separate component — Herd owns it. You can only make it dormant.
Check how pnpm got onto your machine first:
ls -la "$(which pnpm)"
# -> .../node/vX/bin/pnpm -> ../lib/node_modules/corepack/dist/pnpm.jsIf that symlink points into corepack/dist/pnpm.js, pnpm is a Corepack shim, not a real install. There is no npm/brew package to remove. Disable the shim and clear the content-addressed store:
corepack disable pnpm # removes the pnpm shim from PATH
rm -rf ~/Library/pnpm # store (v10/v11), global, bin — often >1 GBCorepack itself stays, so corepack enable pnpm brings pnpm back if you ever need it.
Nub's CLI is flag-for-flag compatible with pnpm and reads/writes native lockfiles (npm/pnpm/Bun round-trip; Yarn read-only), so existing projects keep working — just run nub install.
# Homebrew (recommended on macOS — installs outside any managed Node)
brew install nubjs/tap/nub
# or curl
curl -fsSL https://nubjs.com/install.sh | bashAvoid npm install -g @nubjs/nub if that npm belongs to a version-managed Node (nvm/Herd/Volta). The nub launcher then execs a native binary that lives inside that Node's node_modules, so deleting the Node deletes Nub. Homebrew/curl avoid this trap.
Most of "optimize as much as possible" is already handled by defaults on modern hardware:
| Factor | Optimum | Why |
|---|---|---|
| Node ≥ 22.15 / 23.5 / 24.0 | Fast Tier | sync module.registerHooks(), ~2.9× faster startup than tsx |
| APFS / btrfs filesystem | reflink materialization | copy-on-write links from store into node_modules, near-zero extra disk |
| Store on same volume as projects | reflink instead of copy | reflink only works within one volume |
The few knobs worth touching:
NUB_CACHE_DIR— global content store (default$XDG_DATA_HOME/nub/store/v1, i.e.~/.local/share/nub/store/v1). Only change it to keep the store on the same volume as your code if your projects live on a secondary/external disk; otherwise Nub silently falls back to byte-copy.NUB_CONCURRENCY— parallel network/install ops. Auto-tuned; only raise on a fast, unmetered connection (registry rate-limiting can make higher slower).nub install --prefer-offline— skip network revalidation when the store already has everything. Handy as a daily alias:alias ni='nub install --prefer-offline'
- Leave the security defaults on.
paranoid(OS build jail),minimumReleaseAge(24h package cooling window), andadvisoryCheck(OSV) trade a little speed for real safety — don't disable them to "optimize." - Don't set
NODE_COMPATorNODE_EXECUTABLEglobally — they're debugging/override escape hatches that disable Nub's augmentation or pin a specific binary.
Functionally yes — Nub has a built-in Node version manager:
nub node install 24 # provision into Nub's cache
nub node pin <version> # write the project pin
nub node which # resolved binary path
nub node ls / uninstallIt auto-provisions Node when running files, honoring (in priority): NODE_EXECUTABLE → package.json#devEngines → .node-version → .nvmrc → package.json#engines.
But you cannot cleanly "uninstall Herd's nvm" as a standalone thing:
- Herd owns it. The nvm lives inside Herd's app config (
~/Library/Application Support/Herd/config/nvm). Herd's GUI manages versions there and auto-installs the latest by default. There's no supported "remove just the nvm" action, and Herd may re-provision Node. - Shell injection is separate. Herd writes this into
~/.zshrc:Nub won't be your Node manager until those lines are removed and Nub's shim wins PATH ordering.export NVM_DIR="$HOME/Library/Application Support/Herd/config/nvm" [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
- Install Nub via Homebrew/curl so it no longer depends on Herd's Node (see §2).
- Hand Node to Nub:
nub node install 24, verify withnub node which. - Remove the
NVM_DIRexport +nvm.shsource from~/.zshrc(keep Herd's PHP lines — that's Herd's actual job). UnsetNVM_DIR. - Optional: delete
~/Library/Application Support/Herd/config/nvm/versions/*to reclaim disk. Herd may re-download unless you disable its Node feature in settings.
Herd stays your PHP/nginx environment; its Node subsystem just goes unused and off your PATH. That's the realistic outcome — dormant, not surgically removed.
- Nub install / package manager: https://nubjs.com/docs/install
- Nub runtime / version manager: https://nubjs.com/docs/runtime
- Nub repo: https://github.com/nubjs/nub
- Herd Node docs: https://herd.laravel.com/docs/windows/technology/node-versions
- Herd "disable Node feature" issue: beyondcode/herd-community#388