Update Node.js with the tool that installed your active copy. For nvm, run nvm install --lts followed by nvm use --lts. For a Windows LTS installer managed by winget, use winget upgrade --id OpenJS.NodeJS.LTS --exact. On macOS, upgrade the Homebrew formula you actually installed. Verify the active executable before choosing a route.
Use an actively supported LTS release unless you deliberately need Current. After switching versions, check Node and npm, test the project, and rebuild incompatible native addons before deploying.
Latest release with newest features. Best for experimentation.
Long-Term Support — the version to use in production.
How to update Node JS to the latest version
First run node --version and node -p "process.execPath". Then choose the matching method below. These are alternatives; running every installer can leave several conflicting Node copies on PATH.
| Existing installation | Upgrade route | Check before switching |
|---|---|---|
| nvm on macOS/Linux | nvm install --lts, then nvm use --lts | A project .nvmrc can select a different version |
| fnm on Windows/macOS/Linux | fnm install --lts, then fnm use --lts | Initialize the fnm shell environment first |
| Windows winget LTS package | winget upgrade --id OpenJS.NodeJS.LTS --exact | Confirm it appears in winget list |
| Homebrew | brew update, then brew upgrade node or your installed node@MAJOR formula | Unversioned node follows the newest stable release, not an LTS-only policy |
| Official Node installer | Install the supported LTS package for your OS and architecture | Reopen the terminal and check PATH |
| Linux distribution package | Upgrade nodejs through the configured repository | Check which major that repository supplies |
For a specific target major, use a version-manager command such as nvm install 24 or fnm install 24, then select it and run the project tests. Updating npm with npm install -g npm does not update the Node runtime.
Jump to:
- Pre-flight: check your current Node version
- LTS vs Current: which one to install
- Version manager comparison
- Method 1: nvm (Linux and macOS)
- Method 2: fnm (fast, cross-platform)
- Method 3: Volta (project-pinned via package.json)
- Method 4: n (simple alternative to nvm)
- Method 5: Direct download from nodejs.org
- Method 6: OS package managers (apt, dnf, brew, winget)
- Method 7: Windows specifics
- Method 8: Docker base images
- CI/CD: GitHub Actions setup-node
- Per-project version pinning
- After updating: rebuild native modules
- Keep npm, yarn, and pnpm aligned
- Troubleshooting common upgrade issues
- Modern alternatives: Bun and Deno
- FAQ
Pre-flight: check your current Node version
Before any upgrade, capture the current state:
node --version # e.g. v20.19.0
npm --version # e.g. 10.2.3
which node # tells you which install is on PATHwhich node is the most important diagnostic. On Windows it is where node in Command Prompt, but in PowerShell where is an alias for Where-Object, so use where.exe node or Get-Command node there. If it prints /usr/local/bin/node, you have a system install. If it prints ~/.nvm/versions/node/v24.10.0/bin/node, you are on nvm. If it prints ~/.volta/bin/node, you are on Volta. The upgrade path follows the install path.
If node is not found, it may be absent or missing from this shell's PATH. Check the version-manager initialization before installing another copy.
LTS vs Current: which one to install
Node.js ships two release lines in parallel:
| Line | What it means | Where things stand in September 2026 |
|---|---|---|
| Active LTS | The release production should target. About 12 months in this state. | Node 24 (Krypton), Active until 20 October 2026 |
| Maintenance LTS | The previous LTS. Critical bug fixes and security only, for about 18 more months. | Node 22 (Jod), until 30 April 2027 |
| Current | The newest major, where new V8 features land first. | Node 26, promoted to LTS on 28 October 2026 |
| End of life | No fixes at all, security included. | Node 20, 21, 23 and 25. Node 20 ended on 30 April 2026 |
Under the release schedule through Node 26, an even major is released in April or May as Current. Even-numbered majors are promoted to Active LTS that October, and that promotion is what makes them the safe production target. Support then runs about 36 months from release: roughly 12 months Active, then about 18 months Maintenance. Odd-numbered majors historically did not enter LTS. Starting with Node 27, Node is moving to an annual cycle in which every major is intended to enter LTS; see the current release policy.
If you are still on Node 20, you are on an end-of-life release. It stopped receiving security patches on 30 April 2026, and so did Node 25 on 1 June 2026. Those are the two upgrades worth doing today rather than this quarter.
Pick LTS unless you have a specific reason to be on Current. Libraries on npm declare engines.node ranges that target LTS, and your CI matrix should mirror that.
For the live numbers, the Node Versions card at the top of this page is fetched from the Node.js release feed and refreshes hourly. The official release schedule is the authority on what is supported on any given day.
Version manager comparison
| Tool | Platforms | Speed | Auto-switching | Pinning file | Best for |
|---|---|---|---|---|---|
| nvm | Linux, macOS (Bash) | Slow on shell startup | Manual or nvm use | .nvmrc | The default; tons of tutorials reference it |
| nvm-windows | Windows only | OK | Manual | None | Windows users wanting nvm syntax |
| fnm | Linux, macOS, Windows | Very fast (Rust) | Yes (via shell hook) | .nvmrc or .node-version | Anyone tired of nvm slowness |
| Volta | Linux, macOS, Windows | Fast | Yes (per-project, transparent) | package.json "volta" key | Existing setups only. Unmaintained since 2025, see below |
| mise | Linux, macOS, Windows (WSL) | Very fast (Rust) | Yes (.mise.toml, .node-version) | .mise.toml or .node-version | Teams wanting repo-pinned versions, and Volta's recommended successor |
| n | Linux, macOS | Fast | Manual (n auto) | .n-node-version, .node-version, .nvmrc | Simple use-cases, no shell init hook needed |
| asdf | Linux, macOS | OK | Yes (.tool-versions) | .tool-versions | Polyglot devs managing Node + Ruby + Python + Go in one tool |
If you cannot decide: fnm for a personal machine, mise for a team monorepo where you want everyone on the same version automatically. I used to recommend Volta for that second case, and I no longer do, because its maintainers have stood it down.
Method 1: nvm (Linux and macOS)
nvm is the most widely documented Node version manager. It is a Bash script that shims node, npm, and npx to whichever installed version is currently selected.
Install nvm (or update to the latest release):
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.7/install.sh | bash
# Reload your shell, or:
source ~/.bashrc # or ~/.zshrc on macOSList available versions and install LTS:
nvm list-remote --lts # see all LTS releases
nvm install --lts # install the latest LTS
nvm install 24.10.0 # or a specific version
nvm install node # the absolute latest (Current)Switch versions and set a default:
nvm use --lts # this shell only
nvm alias default 'lts/*' # default for new shells
nvm current # show the active version
nvm ls # list locally installed versionsPer-project switching with .nvmrc:
echo "24" > .nvmrc # or "lts/*", "24.10.0"
nvm use # reads .nvmrc in the cwdTo auto-switch when you cd into a project, add a shell hook to your .bashrc or .zshrc (the nvm README has the snippet). The default nvm cd hook is slow because it spawns a subshell; fnm and Volta both do this faster.
To remove an old version after the upgrade:
nvm uninstall 20.19.0Method 2: fnm (fast, cross-platform)
fnm (Fast Node Manager) is a Rust rewrite of nvm. Same conceptual model, dramatically faster shell startup, works on Windows in addition to Linux and macOS.
Install fnm:
# Linux / macOS
curl -fsSL https://fnm.vercel.app/install | bash
# Windows (PowerShell)
winget install Schniz.fnm
# macOS via Homebrew
brew install fnmAdd the shell hook (this is what enables auto-switching on cd):
# ~/.zshrc or ~/.bashrc
eval "$(fnm env --use-on-cd)"
# PowerShell ($PROFILE)
fnm env --use-on-cd | Out-String | Invoke-ExpressionInstall and use:
fnm install --lts
fnm install 24.10.0
fnm use --lts # or a specific version
fnm default lts-latest # default for new shells
fnm list # local
fnm list-remote # remotePer-project pinning works with both .nvmrc and .node-version files:
echo "22" > .node-version # fnm reads either
cd into-this-dir-and-watch # fnm auto-switchesThe --use-on-cd hook makes fnm read the pinning file every time you change directories. No conscious step, no forgotten version.
Method 3: Volta (project-pinned via package.json)
Volta takes a different approach: instead of a global "active version", every project declares its own Node and package manager versions in package.json, and Volta transparently switches when you run a command in that directory.
Read this before you install it. Volta's own README now opens with "Volta is unmaintained". The maintainers say existing installs should keep working for the foreseeable future, so there is no emergency, but they will not fix breakage from new OS releases, and they recommend migrating to mise. If you already run Volta, the section below still describes it accurately and you can stay put for now. If you are choosing a tool today, choose fnm or mise instead, and put the Volta migration on your roadmap.
The mise equivalents of the Volta commands below are short:
mise use --global node@lts # set the global default
mise use --pin node@lts # pin this project, writes .mise.toml
mise upgrade node # move to the newest matching releaseInstall Volta:
# Linux / macOS
curl https://get.volta.sh | bash
# Windows
winget install Volta.VoltaInstall Node and set the project version:
volta install node@lts # globally available
volta install node@24.10.0
volta install npm@10 # pin npm version too
# Inside a project:
volta pin node@22 # writes "volta" key into package.json
volta pin npm@10This adds to package.json:
{
"volta": {
"node": "24.10.0",
"npm": "10.9.0"
}
}Every developer (and CI) who runs node or npm inside that repo gets exactly those versions, automatically. No shell hooks, no remembering to run nvm use. This is the best option for teams because the version pinning lives in source control where everyone benefits.
The catch: Volta does not manage Yarn 2+ Berry or pnpm out of the box as cleanly as it manages Node and classic npm/Yarn. For pnpm, see the Volta pnpm docs.
Method 4: n (simple alternative to nvm)
n is a minimalist version manager: no shell init hook, no PATH manipulation beyond installing to /usr/local. Originally written by TJ Holowaychuk.
# Install n itself (requires Node already installed, or use n-install)
npm install -g n
# Install the latest LTS
sudo n lts
# Install latest current
sudo n current
# Install a specific version
sudo n 24.10.0
# List installed versions
n ls
# Switch interactively (arrow keys)
sudo nn installs Node binaries to /usr/local/n/versions/node/<version> and symlinks the active one to /usr/local/bin/node. Because it touches /usr/local, you need sudo (or a writable prefix via N_PREFIX).
n is appealing because it has no shell-startup overhead, but it lacks per-directory auto-switching. If you only ever work on one Node project at a time, n is plenty.
Method 5: Direct download from nodejs.org
For machines where you cannot or do not want to install a version manager (locked-down corporate laptops, kiosks, single-purpose servers), the official installer from nodejs.org/en/download is the right answer.
- Visit nodejs.org/en/download
- Choose LTS unless you need Current
- Pick the right installer for your OS and architecture (Windows
.msi, macOS.pkgUniversal/Intel/Apple Silicon, Linux tar.xz) - Run it; it replaces any existing install of the same major
- Open a new terminal (the old one has the stale PATH) and verify:
node --version
npm --versionThe macOS .pkg installer is universal as of Node 16+ and runs natively on both Intel and Apple Silicon. The Windows .msi adds Node to PATH and ticks the "install build tools" option if you want native-addon compilation.
This method does not support side-by-side versions. To switch between majors after using the installer, install a version manager and let it take over.
Method 6: OS package managers (apt, dnf, brew, winget)
OS package managers ship Node too, but their versions usually lag behind the official release line by months. They are fine for ad-hoc scripts and Docker base images, but most production Node apps want a specific version that the OS repo does not have.
Ubuntu / Debian (apt) via NodeSource, which provides separate repositories for Node major versions:
# Latest LTS
curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash -
sudo apt-get install -y nodejs
# A specific major (e.g. Node 22)
curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -
sudo apt-get install -y nodejsRHEL / Fedora / Rocky / Alma (dnf) via NodeSource:
curl -fsSL https://rpm.nodesource.com/setup_lts.x | sudo bash -
sudo dnf install -y nodejsmacOS Homebrew:
brew update
brew install node # latest stable
brew install node@24 # specific major
brew upgrade node # upgrade in place
brew info node@24 # follow its PATH instructions if selecting this formulaWindows winget:
To upgrade Node via winget, run winget upgrade OpenJS.NodeJS (current line) or winget upgrade OpenJS.NodeJS.LTS (the LTS package). The two package IDs are OpenJS.NodeJS for the Current release and OpenJS.NodeJS.LTS for LTS, so pick the one matching what you have installed.
# Install (first time)
winget install OpenJS.NodeJS.LTS # LTS package
winget install OpenJS.NodeJS # Current package
# Upgrade in place
winget upgrade OpenJS.NodeJS # Current
winget upgrade OpenJS.NodeJS.LTS # LTSwinget upgrade only manages Node if winget (or the matching .msi) installed it in the first place. A Node that came from nvm-windows, fnm, Volta, or a raw archive is not tracked by winget, so winget upgrade will report nothing to update; upgrade those through their own tool instead. Check what owns your install with winget list OpenJS.NodeJS.
Windows Chocolatey:
choco install nodejs-lts
choco upgrade nodejs-ltsThe downside of every package-manager route is that you cannot easily switch back if the new version breaks something. If that matters, use a version manager.
Method 7: Windows specifics
Windows has the most install options because nvm itself does not run natively on Windows.
| Tool | Notes |
|---|---|
| nvm-windows | Different project from Unix nvm. Similar commands, runs natively. See github.com/coreybutler/nvm-windows. |
| fnm | Best modern choice on Windows. winget install Schniz.fnm. Same commands as Unix. |
| Volta | Native Windows installer, repo-pinned versions via package.json. |
| winget | Built-in. winget install OpenJS.NodeJS.LTS. No version switching. |
| Chocolatey | choco install nodejs-lts. Common on dev-heavy Windows machines. |
| Direct .msi | nodejs.org installer. Optional "build tools" checkbox installs Python and Visual Studio C++ workloads for native addons. |
Install only one Node manager on a Windows machine at a time. They all manipulate PATH and the active node.exe shim differently, and combining (e.g. nvm-windows + winget Node) leads to "which node is on PATH" mysteries that take an hour to unwind.
For PowerShell auto-switching with fnm, add this to $PROFILE:
fnm env --use-on-cd | Out-String | Invoke-ExpressionMethod 8: Docker base images
Inside Docker, "updating Node" means changing the FROM line.
# Pin to an LTS major. Recommended for production.
FROM node:22-alpine
# Pin the Node patch; the image tag itself can still be rebuilt.
FROM node:24.10.0-alpine
# Convenience tag tracking whatever the current LTS is.
FROM node:lts-alpine
# Bigger but with more system libraries available.
FROM node:22-bookworm-slimThe node: images are built and published by the Node Docker team. Use -alpine for the smallest footprint (musl libc, ~50 MB) or -slim if you need glibc compatibility (closer to ~70 MB).
To upgrade an existing service:
- Change
FROM node:20-alpinetoFROM node:22-alpinein the Dockerfile - Rebuild, pulling a fresh base image:
docker build --pull --no-cache -t myapp:24 . - Run the test suite against the new image
- Pay attention to native-addon rebuild output during
npm install(see After updating: rebuild native modules)
Choose the runtime major deliberately. Moving tags, including patch tags, are not immutable images; pin a reviewed digest when you need that guarantee and schedule updates for fixes. node:latest follows the newest stable line, which may be Current.
For multi-arch (Apple Silicon dev, x86 prod), pass --platform=linux/amd64 or use Buildx with --platform linux/amd64,linux/arm64. The node: images are multi-arch by default.
CI/CD: GitHub Actions setup-node
The standard pattern is the actions/setup-node action with a matrix:
name: CI
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [22.x, 24.x]
steps:
- uses: actions/checkout@v7
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v7
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'
- run: npm ci
- run: npm testcache: 'npm' enables npm cache restoration keyed on package-lock.json, the single biggest speedup for any Node CI.
To read the version from .nvmrc or .node-version (so CI matches what local dev uses):
- uses: actions/setup-node@v7
with:
node-version-file: '.nvmrc'
cache: 'npm'Or, for projects using Volta, the action reads package.json:
- uses: actions/setup-node@v7
with:
node-version-file: 'package.json' # reads "volta.node"For Docker-based CI, base the build off node:22-alpine and skip setup-node entirely.
Per-project version pinning
Pinning Node per project means every developer (and CI) ends up on the same major. Four ways, in order of how much they cover:
| File | Read by | What it pins |
|---|---|---|
.nvmrc | nvm, fnm, GitHub actions/setup-node | Node only |
.node-version | fnm, asdf, GitHub actions/setup-node | Node only |
package.json engines.node | npm (warns on mismatch), yarn (errors), pnpm (errors with engine-strict=true) | Min Node, advisory |
package.json volta | Volta, GitHub actions/setup-node | Node AND package manager |
A real-world package.json snippet:
{
"name": "my-app",
"engines": {
"node": ">=22.0.0 <23.0.0",
"npm": ">=10.0.0"
},
"volta": {
"node": "24.10.0",
"npm": "10.9.0"
}
}engines is advisory unless paired with engine-strict=true in .npmrc:
# .npmrc
engine-strict=trueWith that flag, npm install will fail (not warn) when run on a Node version outside the range. This is the pattern teams want for libraries so that nobody accidentally publishes a build from an unintended Node.
After updating: rebuild native modules
This is the post-upgrade step most articles skip. Native Node modules (anything that compiles C/C++ via node-gyp) are tied to the Node ABI for the major version they were built against. After a major upgrade, those .node binaries no longer load, and you get errors like:
Error: The module '/path/to/binding.node' was compiled against a different Node.js version using NODE_MODULE_VERSION 108. This version of Node.js requires NODE_MODULE_VERSION 115.
The fix:
npm rebuild
# or, to be thorough:
rm -rf node_modules package-lock.json
npm installCommon native-module culprits to test specifically after a major upgrade:
bcrypt,argon2(password hashing)sharp(image processing)better-sqlite3,sqlite3,canvasnode-sassis end-of-life (July 2024) and will not build on a modern Node. Migrate tosass(Dart Sass) instead of trying to rebuild it.canvas,node-canvasnode-pty,node-serialport- Any module shipping a
binding.gyp
For Docker, the rebuild happens inside the image build because npm install runs against the new Node base. As long as you do not mount a host node_modules into the container, you are fine.
If the rebuild itself fails, you are usually missing build tools. On Linux: sudo apt-get install -y build-essential python3. On macOS: xcode-select --install. On Windows: re-run the Node .msi and tick "install tools for native modules" (current installers bundle them). Do not reach for the old npm install -g windows-build-tools package; it is deprecated and unmaintained.
Keep npm, yarn, and pnpm aligned
A Node major upgrade often ships a new bundled npm. Verify:
node --version # v22.x
npm --version # 10.x bundledTo upgrade npm independently of Node:
npm install -g npm@latest
npm install -g npm@10 # pin a majorFor Yarn (the classic v1 line):
npm install -g yarn@1For Yarn 2+ (Berry), Yarn ships per-project via corepack:
corepack enable # one-time
corepack use yarn@4.5.0 # pins it in package.jsonFor pnpm, the recommended path in 2026 is also corepack:
corepack enable pnpm
corepack use pnpm@9.12.0 # pins it in package.jsoncorepack is the official Node way to manage package-manager versions per project: a packageManager field in package.json declares the exact pnpm or yarn version, and corepack use writes it for you.
Two things changed recently and both bite on a fresh machine. Corepack is no longer bundled with Node. It shipped with Node from 14.19.0 up to but not including 25.0.0, so a clean Node 25 or 26 install has no corepack binary and you need npm install -g corepack before corepack enable. Node 24, the current LTS, still bundles it. And corepack prepare ... --activate is deprecated. Use corepack use <pkg>@<version> to pin a project, or corepack install -g <pkg>@<version> to set a system-wide default.
Troubleshooting common upgrade issues
node: command not found after install. PATH has not picked up the new install. Open a fresh terminal. If still missing, run which node || echo missing and check that the install directory (e.g. ~/.nvm/versions/node/v24.10.0/bin) is on $PATH. For nvm/fnm/Volta, make sure their shell-init line is in ~/.bashrc or ~/.zshrc.
Version manager does not auto-switch on cd. You have not added the hook. For fnm: eval "$(fnm env --use-on-cd)" in your shell rc file. For nvm: copy the auto-switching snippet from the nvm README into your rc file.
EACCES: permission denied errors after switching versions. npm global directory is owned by root from a previous sudo-install. If you are not using a version manager, point the npm prefix at a user-owned directory (npm config set prefix ~/.npm-global and add ~/.npm-global/bin to PATH). Do not do this under nvm. nvm's README states plainly that it is not compatible with the npm prefix option, and setting one breaks nvm use. Under nvm, fnm, or Volta the fix is the other way round: remove any custom prefix (npm config delete prefix) and let globals live inside the version manager's own directory.
node-gyp errors during install. Native build tools missing. Linux: sudo apt-get install -y build-essential python3. macOS: xcode-select --install. Windows: re-run the Node .msi with build-tools option.
Old PATH lingering after Homebrew upgrade. Run brew doctor and follow its instructions. hash -r (bash/zsh) clears the shell command cache so it re-finds node.
Two version managers fighting. Symptom: which node prints a path you did not expect, or node --version and nvm current disagree. Pick one manager, uninstall the other (brew uninstall node, nvm uninstall, etc.), and reload the shell.
Docker container uses old Node despite Dockerfile change. You are running a cached image. Rebuild with docker build --pull (--no-cache alone reuses the base image you already have) or bump the tag (myapp:22) so the orchestrator pulls fresh.
Production server still serves old version after apt upgrade. systemd is running a long-lived process spawned with the old binary. sudo systemctl restart <service> to pick up the new Node.
For server-admin patterns adjacent to this (managing remote machines, exporting and importing SSH configs), see How to Export and Import PuTTY Settings. For the shell scripting toolkit you will write upgrade scripts in, Bash For Loops and Bash While Loops cover the iteration patterns.
Modern alternatives: Bun and Deno
If you are upgrading Node anyway, it is worth knowing what else is in the runtime market in 2026.
| Runtime | Compatible with Node? | When to consider |
|---|---|---|
| Bun | Mostly yes (Node API + npm) | New projects wanting faster startup and bundled tooling (test runner, bundler, SQLite client). Drop-in for many Node scripts. |
| Deno | Yes via npm: specifiers and Node compatibility mode | Greenfield TypeScript projects, secure-by-default sandboxing, single-binary deploys. |
| Node.js | (itself) | Everything else: largest ecosystem, longest track record, mature LTS, every npm library tested against it first. |
For an existing Node app, the answer is almost always "upgrade Node, do not switch runtime". For a fresh CLI or experimental service, Bun and Deno are worth a 30-minute spike. Their compatibility with native addons is the main caveat: if your app depends on sharp, better-sqlite3, or anything that ships a .node binary, the Node path is the safer bet for now.
Related Node.js guides
This page is the hub of a small Node.js cluster. The companion guides go deeper on each step:
- How to install Node.js: get the runtime onto a fresh Linux, macOS, or Windows box in the first place.
- How to check your Node.js and npm version: the one-liners, and what
which nodeactually tells you about your install. - Node.js LTS vs Current: which release line to run, the support windows, and why LTS wins for production.
- nvm vs fnm vs Volta: pick the version manager that fits how you work.
- Pin a Node.js version per project:
.nvmrc,.node-version,engines, and thevoltakey, so the whole team runs the same Node. - Fix NODE_MODULE_VERSION mismatch: the native-module rebuild error that bites right after an upgrade.
- Node.js in GitHub Actions:
setup-node, dependency caching, and the version matrix for CI. - How to uninstall Node.js: remove it cleanly, whichever way you installed it.
What to do next
If you got this page open while debugging a production incident, the next steps usually look like:
- How to Dockerize a Node.js App: the multi-stage Dockerfile that pins the exact Node version your container runs, so the image and your local install never drift.
- How to Write a Dockerfile: the
FROM node:line and layer order behind the base-image upgrade in Method 8 above. - Bash For Loops: the iteration patterns for scripting the upgrade across a fleet of servers.
- Bash While Loops: the wait-until-healthy and retry-with-backoff patterns for the post-deploy check.
- Export or Backup All MySQL Databases: take a database snapshot before any production runtime upgrade.
FAQ
Run the upgrade command that matches how Node was installed. With a version manager: nvm install --lts, fnm install --lts, or volta install node@lts. With a package manager: brew upgrade node on macOS, winget upgrade OpenJS.NodeJS on Windows, or NodeSource on Linux (curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash - && sudo apt-get install -y nodejs). From nodejs.org, download the latest LTS installer and re-run it.
To upgrade the node version to a specific major instead of the latest, replace --lts with the number (nvm install 24.11.0). Always run node --version afterwards to confirm the update took, and npm rebuild if the project uses native modules.
Node.js follows a strict release cadence: a new major even-numbered LTS line every April, supported for 30 months. The Node Versions card at the top of this page shows the current LTS and Current versions live from the Node.js release feed, so it is always accurate.
Pick LTS for production. The matching Maintenance LTS (previous major) is the safe fallback if a regression in the new line blocks you.
Run nvm install --lts to install the latest LTS, then nvm use --lts to activate it for the current shell, and nvm alias default 'lts/*' so future shells get the same version.
To remove old versions after upgrading: nvm uninstall 20.19.0. To list everything you have installed locally: nvm ls.
Use winget upgrade OpenJS.NodeJS.LTS, or download the latest LTS .msi from nodejs.org/en/download and run it. The installer replaces the previous version in place; global npm packages installed under the user prefix survive the upgrade. PATH entries are preserved.
For version switching (keeping multiple Node majors side-by-side), install fnm (winget install Schniz.fnm) or nvm-windows first, then use those to install and switch between versions.
Use fnm for a fresh setup. It is faster, cross-platform (Linux, macOS, Windows), and reads the same .nvmrc files as nvm so any existing project pinning still works. Shell startup is noticeably quicker because fnm is a single Rust binary, not a Bash script.
Stay with nvm if you have existing tooling, dotfiles, or team docs that depend on the nvm command syntax and you do not want to migrate. They are functionally equivalent for most workflows.
Three layered options, pick whichever fits your team:
.nvmrcwith a single line like24orlts/*. Read by nvm, fnm, and GitHubactions/setup-node.package.jsonengines,engines: { node: '>=22.0.0' }. Combine withengine-strict=truein.npmrcso installs fail on mismatch instead of just warning.- Volta,
volta pin node@24.10.0writes a"volta"key intopackage.jsonand every developer in the repo transparently gets that exact version.
Native modules (anything with a .node binary, like bcrypt, sharp, better-sqlite3) are compiled against a specific Node ABI. When you upgrade Node majors, the ABI changes and the old binary refuses to load.
The fix is to rebuild: npm rebuild inside the project. If that fails, nuke and reinstall: rm -rf node_modules package-lock.json && npm install. Make sure build tools are present (build-essential on Linux, Xcode Command Line Tools on macOS, the Node MSI build-tools option on Windows).
Change the FROM line in your Dockerfile from, say, node:22-alpine to node:24-alpine, then rebuild with docker build --no-cache -t myapp:22 . Native modules are recompiled automatically during the npm install layer because the install runs against the new Node binary.
Always pin to a major or major.minor in production (node:24-alpine, node:24.10.0-alpine). Never use node:latest, it tracks Current, not LTS, and flips to the next major every October.
In GitHub Actions, use actions/setup-node@v7 with node-version-file: '.nvmrc' (or 'package.json' if the project uses Volta). The action reads the same pinning file your developers use locally, so CI and dev cannot drift.
For multi-version coverage, combine that with a matrix: matrix.node-version: [22.x, 24.x] and use node-version instead of node-version-file. Library authors should test against every LTS in active support.
Sources
Authoritative references this article was fact-checked against.
- Node.js release schedule and LTS timeline (nodejs/Release)github.com
- Node.js downloads (official, nodejs.org)nodejs.org
- nvm (Node Version Manager) READMEgithub.com
- fnm (Fast Node Manager) READMEgithub.com
- Volta documentationdocs.volta.sh
- actions/setup-node (GitHub Actions)github.com
- Official Node.js Docker image tags (Docker Hub)hub.docker.com
- Corepack README, including which Node versions bundle itgithub.com
- mise: Node.js plugin documentationmise.jdx.dev
- Node-API (N-API) ABI stability: Node.js documentationnodejs.org
- Node Sass is end of life: Sass blogsass-lang.com





