~/home

Upgrading Node under pm2 without the surprises

· node, pm2

TL;DR: When upgrading Node.js with nvm under pm2, pin nvm alias default to a major version, update the saved PATH in ~/.pm2/dump.pm2 for fork-mode apps, regenerate the pm2 systemd unit with the new node binary, and check readlink /proc/PID/exe before uninstalling the old version.

A security release came out, so I moved a few pm2 apps to a newer Node with nvm. nvm install took a minute. Finding every place the old version was still hiding took longer. Here is the order that worked with one restart per app.

1. Pin the nvm default to a major version

If your default is lts/*, nvm rewrites that alias every time it fetches the remote list. When a new line goes LTS, default points at a version you never installed, and new shells start with no node at all.

nvm install 24 --reinstall-packages-from=22
nvm alias default 24

--reinstall-packages-from reinstalls the same pm2 version you had, not the latest one. That's what you want here.

2. Fork-mode apps remember the old PATH

pm2 saves each app's environment in ~/.pm2/dump.pm2. Fork-mode apps spawn node through the saved PATH, so after a daemon restart they quietly keep running the old binary. Cluster-mode apps follow the daemon's own node.

Back up the dump, then replace the old version string in PATH, NVM_BIN, NVM_INC and _. pm2 restart --update-env also works, but run from a non-interactive SSH command it picks up that shell's thinner PATH.

3. Regenerate the systemd unit

The unit made by pm2 startup hard-codes the node path. Generate it again with the new binary:

NEW=$HOME/.nvm/versions/node/v24.x.y
sudo env PATH=$NEW/bin:$PATH $NEW/bin/node $NEW/lib/node_modules/pm2/bin/pm2 \
  startup systemd -u $USER --hp $HOME
sudo systemctl daemon-reload
sudo systemctl restart pm2-$USER

Avoid pm2 update over SSH for this. It restarts the daemon inside your SSH session's scope instead of under systemd.

4. Verify, then uninstall

for p in $(pgrep -f node); do readlink /proc/$p/exe; done | sort | uniq -c
pm2 save

Only when nothing points at the old version, run nvm uninstall.