Installing Node.js is genuinely simple, but the best way to install it depends on the machine: on a development laptop you almost always want a version manager (so you can hold several Node majors side by side and never need sudo for a global package), whereas on a single-purpose server or a locked-down work laptop the official installer or your OS package manager is the pragmatic choice. I have set Node up on my own machines, on production boxes, and inside CI more times than I can count, and the one mistake that bites people is reaching for apt install nodejs on day one and ending up stuck on a version that is a year behind. Below is how to install Node.js on each OS the way I actually do it, with the verification step and the most common first-install snags.
Latest release with newest features. Best for experimentation.
Long-Term Support — the version to use in production.
How do I install Node.js?
The fastest reliable way to install Node.js is with a version manager. On Linux or macOS, install fnm (curl -fsSL https://fnm.vercel.app/install | bash), then fnm install --lts and fnm use lts-latest. On Windows, winget install Schniz.fnm then the same fnm install --lts. If you do not want a version manager, download the LTS installer from nodejs.org/en/download and run it (Windows .msi, macOS .pkg, Linux tarball). On Ubuntu/Debian use NodeSource (curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash - && sudo apt-get install -y nodejs) rather than the stale distro nodejs package. On macOS Homebrew, brew install node. After any method, verify with node --version and npm --version in a fresh terminal. Choose LTS, not Current, unless you have a specific reason to be on the bleeding edge.
Jump to:
- LTS vs Current: which one to install
- Which installation method should I use?
- Install on Linux (Ubuntu, Debian, Fedora, RHEL)
- Install on macOS
- Install on Windows
- Install with a version manager (recommended for dev)
- Install via the official nodejs.org installer
- Install in Docker
- Verify the install
- Troubleshooting a fresh install
- FAQ
LTS vs Current: which one to install
Node.js ships two release lines at once, and picking the wrong one is the most common first-install misstep:
| Line | Versions | Released | Supported | Install this if |
|---|---|---|---|---|
| LTS | Even majors (20, 22, 24) | April | 30 months | You are building anything real: apps, libraries, production services |
| Current | Odd majors (21, 23, 25) | October | 6 months | You want to test new V8/language features before they reach LTS |
Pick LTS. Almost every npm library declares engines.node ranges that target LTS, and the Active LTS line is what gets the longest support window. Current is fine to kick the tyres on, but it goes end-of-life in six months and you will be reinstalling. The live card above pulls the exact current LTS and Current numbers from the Node.js release feed.
Which installation method should I use?
| Method | Platforms | Multiple versions? | Needs sudo/admin? | Best for |
|---|---|---|---|---|
| fnm | Linux, macOS, Windows | Yes | No | Modern default; fast, cross-platform |
| nvm | Linux, macOS | Yes | No | The most-documented option (Bash script) |
| Volta | Linux, macOS, Windows | Yes (repo-pinned) | No | Teams pinning Node per project via package.json |
| nodejs.org installer | Linux, macOS, Windows | No | Yes | Locked-down or single-purpose machines |
| NodeSource (apt/dnf) | Linux | No | Yes | Servers, Docker, current versions from a repo |
| Homebrew | macOS, Linux | Limited | No | Mac devs already living in brew |
| winget / Chocolatey | Windows | No | Yes | Windows machines, scripted provisioning |
| Docker | Anywhere | Per image | No | Containers; "install" means the FROM line |
If you only take one recommendation: use fnm on a personal machine, Volta on a team repo, and the official installer or NodeSource where you cannot install a version manager.
Install on Linux (Ubuntu, Debian, Fedora, RHEL)
Do not use the distro's own nodejs package as your first move. Ubuntu's apt repo, for example, often ships a Node major that is well behind the current LTS, and you cannot easily switch off it later. Use NodeSource, which mirrors the official release line.
Ubuntu / Debian (apt):
# Latest LTS
curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash -
sudo apt-get install -y nodejs
# Or a specific major (e.g. Node 22)
curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -
sudo apt-get install -y nodejsFedora / RHEL / Rocky / Alma (dnf):
curl -fsSL https://rpm.nodesource.com/setup_lts.x | sudo bash -
sudo dnf install -y nodejsNodeSource installs npm alongside Node, so you do not need a separate npm package (and on Debian/Ubuntu installing the distro npm separately can actually conflict). Verify with node --version && npm --version.
If you would rather not pipe a script into bash as root (a fair instinct on a shared server), install fnm under your own user instead, see the version-manager section below. It needs no root and gives you version switching for free.
Install on macOS
Two good options on macOS: Homebrew, or a version manager.
Homebrew (simplest if you already use brew):
brew update
brew install node # latest stable
brew install node@22 # a specific major
node --versionHomebrew's node formula tracks the latest stable, which can be a Current (odd) major rather than LTS. If you need to stay on LTS, install the pinned formula (node@22) and brew link it.
fnm via Homebrew (my preference, gives you version switching):
brew install fnm
echo 'eval "$(fnm env --use-on-cd)"' >> ~/.zshrc
source ~/.zshrc
fnm install --lts
fnm use lts-latestThe macOS .pkg from nodejs.org is also a perfectly good choice and is a Universal binary, running natively on both Apple Silicon and Intel. See the official-installer section.
Install on Windows
Windows has more options than the other platforms because the original Unix nvm does not run there. Pick one and stick to it; mixing two Node installers on Windows is the fastest route to "which node.exe is on PATH" confusion.
| Tool | Install command | Version switching? |
|---|---|---|
| fnm | winget install Schniz.fnm | Yes (best modern choice) |
| winget | winget install OpenJS.NodeJS.LTS | No |
| Chocolatey | choco install nodejs-lts | No |
| nvm-windows | from coreybutler/nvm-windows | Yes |
| Volta | winget install Volta.Volta | Yes (repo-pinned) |
| Direct .msi | from nodejs.org/en/download | No |
For a development machine, install fnm and enable auto-switching in PowerShell by adding this to your $PROFILE:
winget install Schniz.fnm
fnm env --use-on-cd | Out-String | Invoke-Expression
fnm install --lts
fnm use lts-latestFor a build server or a quick one-off, winget install OpenJS.NodeJS.LTS is the least-friction path. The .msi installer also offers a "Tools for Native Modules" checkbox that installs the Python and Visual Studio C++ workloads needed to compile native addons (bcrypt, sharp, and friends); tick it if your projects use any.
Install with a version manager (recommended for dev)
A version manager installs Node under your home directory, lets you hold several majors side by side, switches between them per project, and means you never need sudo for a global npm package. This is how I set up every dev machine.
fnm (Fast Node Manager, a Rust rewrite of nvm; cross-platform and fast):
# Linux / macOS
curl -fsSL https://fnm.vercel.app/install | bash
# add the shell hook (zsh shown; use ~/.bashrc for bash)
echo 'eval "$(fnm env --use-on-cd)"' >> ~/.zshrc
source ~/.zshrc
fnm install --lts # install latest LTS
fnm use lts-latest # activate it
fnm default lts-latest # default for new shellsnvm (the original; Bash script, Linux and macOS only):
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.4/install.sh | bash
source ~/.bashrc # or ~/.zshrc on macOS
nvm install --lts # install latest LTS
nvm use --lts # activate for this shell
nvm alias default --lts # default for new shellsVolta (transparent, repo-pinned versions, great for teams):
# Linux / macOS
curl https://get.volta.sh | bash
volta install node@lts # globally available
# inside a project:
volta pin node@22 # writes a "volta" key into package.jsonWith any of these, pinning a version per project (.nvmrc, .node-version, or the volta key in package.json) keeps every developer and CI on the same major. For a head-to-head on which to choose, see nvm vs fnm vs Volta.
Install via the official nodejs.org installer
For machines where a version manager is not an option (corporate-managed laptops, kiosks, single-purpose servers), the official installer is the right answer:
- Go to nodejs.org/en/download
- Choose LTS unless you specifically need Current
- Pick your OS and architecture (Windows
.msi, macOS.pkgUniversal, Linuxtar.xz) - Run it; it installs Node and the bundled npm, and adds them to PATH
- Open a new terminal (the old one has a stale PATH) and verify
node --version
npm --versionThis method does not give you side-by-side versions: to switch majors later you would reinstall, or install a version manager and let it take over. The macOS .pkg is a Universal binary (native on both Apple Silicon and Intel); the Windows .msi includes the optional native-module build-tools step.
Install in Docker
Inside a container you do not install Node at all, you base the image on an official node: image and pin the version in the FROM line:
# Pin to an LTS major. Recommended for production.
FROM node:22-alpine
# Pin to an exact patch for fully reproducible builds.
FROM node:22.11.0-alpine
# Tracks whatever the current LTS is (convenient, less reproducible).
FROM node:lts-alpineUse -alpine for the smallest image (musl libc, around 50 MB) or -slim (Debian, glibc) when a dependency needs glibc compatibility. Always pin to a major or major.minor in production: never node:latest, which follows Current and will flip majors on you every October. For the full multi-stage pattern, see How to Dockerize a Node.js App.
Verify the install
Whatever method you used, confirm it landed:
node --version # e.g. v22.11.0
npm --version # e.g. 10.9.0
which node # where node is installed (on Windows: where node)A successful install prints a Node version on the first line and an npm version on the second. which node (or where node) tells you which install is on PATH, which is the diagnostic that resolves nearly every "but I installed it" puzzle: a version manager will print a path under ~/.fnm, ~/.nvm, or ~/.volta; the official installer prints /usr/local/bin/node (macOS/Linux) or a Program Files path (Windows). For a deeper look at reading and comparing versions, see how to check your Node version. When the time comes to move up a major, updating Node.js walks through every upgrade path and the native-module rebuild step.
A quick smoke test that Node actually runs:
node -e "console.log('node ' + process.version + ' works')"
# node v22.11.0 worksTroubleshooting a fresh install
node: command not found right after installing. The shell has a stale PATH. Open a brand-new terminal. If it persists with a version manager, you missed the shell-init line: fnm needs eval "$(fnm env --use-on-cd)" in ~/.zshrc or ~/.bashrc; nvm needs its sourcing snippet (the installer appends it, but only to one rc file).
A very old version came in via apt. You installed the distro nodejs package instead of NodeSource. Remove it (sudo apt-get remove -y nodejs) and reinstall through NodeSource as shown above, or switch to fnm under your user.
EACCES: permission denied installing a global npm package. Your Node lives in a root-owned directory (typical with a system or Homebrew install) and global npm wants to write there. The clean fix is to use a version manager so npm globals live under your home directory; the quick fix is npm config set prefix ~/.npm-global and add ~/.npm-global/bin to PATH. Do not sudo npm install -g, that compounds the problem.
Homebrew installed a Current (odd) major when you wanted LTS. brew install node tracks latest stable. Install the pinned LTS formula instead: brew install node@22 && brew link --overwrite node@22.
node-gyp errors when a dependency compiles. Native build tools are missing. Linux: sudo apt-get install -y build-essential python3. macOS: xcode-select --install. Windows: re-run the .msi and tick the native-modules option.
Two managers fighting. If node --version and fnm current (or nvm current) disagree, you have more than one Node manager installed. Pick one, uninstall the others, and reload the shell.
FAQ
See also
- How to update Node.js: once Node is installed, this covers every upgrade path (nvm, fnm, Volta, the installer, Docker, CI) and the native-module rebuild people forget.
- nvm vs fnm vs Volta: the head-to-head if you are choosing a version manager and want speed, auto-switching, and pinning compared.
- Checking your Node version: how to read
node --version, compare it to a project's requirements, and tell which install is active. - How to Dockerize a Node.js App: the multi-stage Dockerfile behind the
FROM node:line in the Docker section above.
Sources
Authoritative references this article was fact-checked against.





