Automated Node.js version upgrade + global package migration CLI. Cross-platform Β· Multi-manager Β· Zero manual steps.
Every time Node.js ships a new LTS or Current release, you need to:
- Look up the new version on nodejs.org
fnm install <version>(ornvm install, orvolta install node@<ver>, ...)- Snapshot your global
npmpackages from the old version - Switch to the new version and reinstall every package
- Optionally clean up the old version
nodeup collapses all of that into a single command:
nodeup upgradeIt auto-detects your version manager, fetches the latest LTS and Current
from nodejs.org, installs them, snapshots your global packages, migrates
them over, and (optionally) cleans up β all interactively, all resumable.
- π Auto-detects your Node.js version manager:
fnm,nvm,Volta,asdf,mise,n,nodenv,nvm-windows - π¦ Migrates global npm packages across Node versions automatically
- π Cross-platform: macOS, Linux, Windows (incl. ARM64)
- πΎ Single static binary β no runtime, no npm dependency
- π‘οΈ Resumable: snapshots are written to disk before mutation
- π§ͺ Dry-run mode β see the plan before anything changes
- π Zero lock-in: works on top of your existing manager, doesn't replace it
A few things worth knowing before you run nodeup:
nvmis a shell function, not a binary βnodeuptransparently sources~/.nvm/nvm.sh(or$NVM_DIR/nvm.sh) before calling it. No setup required.- Multiple managers installed?
nodeupprompts you to pick one the first time and remembers it in~/.nodeup/config.yaml. You can override per-invocation with--manager <name>. - System Node (e.g. installed via Homebrew, apt, or the Windows
installer) is detected but cannot be upgraded β install a version
manager first if you want
nodeupto manage it. - Bundled packages are always skipped during migration:
npm,corepack, andnpxship with Node itself and are not reinstalled. - Native addons may need a rebuild after a major Node version
bump. If something like
node-sassorsharpmisbehaves, runnpm rebuild -gagainst the new version. - Concurrent runs are blocked via a lock file at the platform
DataDir(resolved byplatform.LockPath()β e.g.~/.local/share/nodeup/nodeup.lockon Linux,~/Library/Application Support/nodeup/nodeup.lockon macOS,%APPDATA%\nodeup\nodeup.lockon Windows). If a run crashes mid-upgrade, the next invocation offers to restore from the snapshot written at the start.
Pick the channel that matches how you manage other tools. Use the matrix below as the entry point β the per-channel sections below it spell out exactly what to run.
| If you⦠| Use | Why |
|---|---|---|
| Already use Homebrew for dev tooling on macOS / Linux | Homebrew | One command, auto-updates with brew upgrade, lives outside any Node install, uninstalls cleanly with brew uninstall. |
| Already use Scoop on Windows | Scoop | Same shape as Homebrew on the Windows side β scoop update nodeup keeps it current, no admin shell needed. |
Already manage dev tools via npm install -g and want a one-liner |
npm wrapper (nodeupx) |
No new package manager to set up; the install travels with the Node version it's installed against. Slight catch: a nodeup upgrade ships when the wrapper version bumps. The npm name is nodeupx because nodeup is taken. |
Are blocked from system package installs but can npm i -g |
npm wrapper | Sandboxed / corp-locked-down machines often allow npm globals where they block system installers. |
Maintain nodeup itself, or want a version pinned to a specific tag without any postinstall network step |
Direct binary download | You choose the exact release; no installer, no auto-update, no Node coupling. Best for reproducible CI installs. |
Are a Go developer hacking on nodeup and want the latest commit |
go install |
Pulls the current source and builds it locally. Fastest iteration loop for contributors. |
brew install dipto0321/tap/nodeupBest for: macOS / Linux users who already use Homebrew for tools. The
formula is auto-managed by GoReleaser from brew: {} in
.goreleaser.yaml, so a v*.*.* tag updates the tap.
scoop bucket add dipto0321 https://github.com/dipto0321/scoop-bucket
scoop install nodeupBest for: Windows users who already use Scoop. The manifest is
auto-managed by GoReleaser from scoop: {} in .goreleaser.yaml.
npm install -g nodeupxThe wrapper is published as nodeupx, not nodeup, because
the bare nodeup name on npmjs.com is owned by an unrelated,
dormant 2015 package (romanmt/nodeup β "a simple cluster
implementation for node"). The downloaded binary still installs
as the nodeup CLI on your $PATH.
Best for: anyone who treats their global npm install as the source
of truth for CLI tools β typical in JavaScript / TypeScript projects.
The wrapper is a thin downloader (scripts/install.js) that fetches
the matching static Go binary from the GitHub release tagged by this
package's binaryVersion field. See
nodeup-npm/README.md for the install
mechanics, updating behavior, and uninstall behavior.
Best for: CI pipelines, lock-down environments, and anyone who wants zero install ceremony. Grab the archive for your OS/arch from the Releases page:
# macOS Apple Silicon
curl -L https://github.com/dipto0321/nodeup/releases/latest/download/nodeup_$(curl -s https://api.github.com/repos/dipto0321/nodeup/releases/latest | grep tag_name | cut -d'"' -f4 | tr -d v)_darwin_arm64.tar.gz | tar xz
sudo mv nodeup /usr/local/bin/
# Linux x86_64
curl -L https://github.com/dipto0321/nodeup/releases/latest/download/nodeup_*_linux_amd64.tar.gz | tar xz
sudo mv nodeup /usr/local/bin/
# Windows (PowerShell)
curl -L https://github.com/dipto0321/nodeup/releases/latest/download/nodeup_$(curl -s https://api.github.com/repos/dipto0321/nodeup/releases/latest | grep tag_name | cut -d'"' -f4 | tr -d v)_windows_amd64.zip -OutFile nodeup.zip
Expand-Archive nodeup.zip -DestinationPath .go install github.com/dipto0321/nodeup/cmd/nodeup@latestRequires Go 1.24+ (matches go.mod and the CI pin). Best for:
nodeup contributors and anyone who wants to track main between
releases.
# See what's available without installing anything
nodeup check
# Upgrade both LTS and Current, migrate global packages, then ask about cleanup
nodeup upgrade
# Just LTS
nodeup upgrade --lts
# Just Current
nodeup upgrade --current
# Plan only β no changes
nodeup upgrade --dry-run
# Non-interactive (CI-friendly)
nodeup upgrade --yesAfter a successful upgrade, nodeup upgrade prompts you about removing old
Node.js versions β answering y deletes all of them, typing a specific
version (e.g. 20.18.0) deletes only that one, and N (or empty enter)
keeps everything. The candidates exclude the new LTS / Current we just
installed plus the version that's currently active on your shell. Skip
the prompt entirely with --no-cleanup or pre-decide with --cleanup.
See docs/managers.md for the
full set of cleanup flags and per-manager behavior.
If you have multiple managers installed, nodeup will prompt you to pick one
the first time and remember it in ~/.nodeup/config.yaml.
nodeup upgrade Upgrade LTS and/or Current
nodeup check Show what's available, install nothing
nodeup list List installed versions via your manager
nodeup packages Manage global package snapshots
nodeup config Manage nodeup configuration
nodeup version Print version info
Run nodeup <command> --help for the full flag reference.
In short:
- Detect which version manager(s) are installed
- Resolve to a single manager (prompt if multiple)
- Fetch the latest LTS and Current from
nodejs.org/dist/index.json - Diff installed vs remote to compute the upgrade plan
- Snapshot the global packages of each version being replaced
- Install the new versions via your manager
- Migrate the snapshots to the new versions
- Cleanup old versions (opt-in)
The optional config file lives at ~/.nodeup/config.yaml:
manager: fnm
track:
lts: true
current: false
packages:
migrate: true
strategy: exact # exact | latest
skip:
- npm
- corepack
cleanup:
auto: false
prompt: true
cache:
ttl: 3600Flags override env vars (NODEUP_MANAGER, NODEUP_TRACK_LTS, NODEUP_CACHE_TTL)
override the file. Manage it with nodeup config {show,get,set,init} β for
example nodeup config set manager fnm writes through to the file (refuses
to write invalid values, refuses to overwrite on init without --force).
See docs/configuration.md for the full schema.
Current release: v1.1.0 (nodeupx@1.0.1 on npm β the npm wrapper
trails the Go binary by one publish). See CHANGELOG.md for the
v1.0.0 β v1.1.0 history.
| Phase | Status | What shipped |
|---|---|---|
| 1 β Detector engine | β | 8/8 managers detected (fnm, nvm, Volta, asdf, mise, n, nodenv, nvm-windows) |
| 2 β Node version API | β | nodeup check + nodejs.org/dist/index.json fetch + TTL cache + HTTP retry/backoff/timeout |
| 3 β Package snapshot/restore | β | nodeup packages {snapshot,restore,diff} + interrupted-upgrade sentinel + MigrationReport |
| 4 β Upgrade command | β | End-to-end nodeup upgrade with snapshot β install β migrate β cleanup |
| 5 β Config subsystem | β | YAML config at ~/.nodeup/config.yaml + config {show,get,set,init} + env vars |
| 6 β Cross-platform polish | β | QuotePath, interrupted-upgrade replay, system-node classifier, lock file |
| 7 β Distribution packaging | β | GoReleaser + brew tap + Scoop bucket + npm wrapper (nodeupx via OIDC Trusted Publishing) |
| 8 β First tagged release | β | v1.0.0 shipped (PR #35); v1.1.0 shipped with the internal/ui rollout (#117/#118/#119) |
Release train: every v*.*.* tag triggers GoReleaser β brew formula
push β Scoop manifest push β nodeupx publish via OIDC. To ship a
new version: see docs/release-checklist.md.
| Topic | Doc |
|---|---|
| Supported version managers, detection, locking to one | docs/managers.md |
| Config schema, precedence rules, env vars | docs/configuration.md |
| Install channels (Homebrew / Scoop / npm / binary / source) | docs/installation.md |
| First-stable + patch release runbook | docs/release-checklist.md |
See CONTRIBUTING.md for the working contract β
branching, Conventional Commits rules, local dev (make ci), PR
workflow, issue / security etiquette, and coding style.
MIT Β© dipto0321