
Who Nvm is for#
Full-stack developers juggling multiple Node.js projects
Switching between a Next.js app pinned to Node 20 and a legacy API on Node 16 takes one command with nvm. A `.nvmrc` in each project root lets shell hooks handle the switch automatically on `cd`, so the right version is always active without manual intervention.
Skip if:
You have a single Node.js project that never changes versions and no legacy codebases. A single system Node.js installation from your package manager is simpler when there is nothing to switch between.
DevOps engineers managing Node.js server deployments
nvm installs without root access, making it suitable for deploying Node.js services in user space on Linux servers. It lets you install a newer Node version alongside the running one and test it before cutting over, with no system package manager involvement.
Skip if:
You run Node.js in Docker containers. A pinned base image (`node:20-alpine`) is more reproducible and requires no runtime version manager inside the container.
CI/CD pipelines requiring specific Node.js versions
nvm's `--lts` flag and named aliases make it straightforward to install the right Node.js version at the start of a CI job. The `BASH_ENV` pattern in the README handles non-interactive shell sourcing in Docker-based CI runners.
Skip if:
Your CI platform (GitHub Actions, CircleCI) already provides a `node-version` input or built-in matrix strategy. Use the platform-native version pinning when available; it is simpler and avoids sourcing nvm inside scripts.
Developers on shared hosting or restricted servers
Because nvm requires no root access and writes only to `~/.nvm`, it works on shared hosting accounts and corporate developer machines where system Node.js was installed by IT. You can install and use any Node.js version without filing a support ticket.
Skip if:
Your environment uses Fish shell or another non-POSIX shell natively. Fish users need a community wrapper; see the README for the available options.
The problem it solves#
Every Node.js developer eventually hits the same wall: one project pins to Node 18 for LTS stability, another needs Node 20 for a specific module, and a third was built on Node 16 and breaks on anything newer. Installing Node.js at the system level means one active version for all of them. Upgrading for one project breaks another, and rolling back requires a full uninstall and reinstall cycle.
The workaround most developers land on before discovering a version manager is to keep a single LTS version and accept that some projects will behave unpredictably, or to spend time debugging failures that are actually just version mismatches. CI/CD pipelines that pin to a specific Node version expose these gaps when a local development version drifts. Manual PATH manipulation to point at different Node binaries is fragile and easy to forget to undo.
How it solves it#
Per-shell Node.js version switching
Set the active Node.js version for the current shell session with `nvm use <version>`. The change is scoped to that shell and does not affect other terminals or other users on the same machine. Running `nvm use 20` in one tab and `nvm use 18` in another works simultaneously.
Per-project version pinning via .nvmrc
Add a `.nvmrc` file to any project directory containing the target Node.js version number or alias (e.g., `20` or `lts/iron`). Shell hooks for bash and zsh can auto-run `nvm use` when you enter the directory, eliminating manual switching entirely.
LTS alias tracking
Install the latest Long-Term Support Node.js release with `nvm install --lts` without looking up the version number. Named aliases like `lts/hydrogen` and `lts/iron` let you pin to a specific LTS line and upgrade within it using `nvm install lts/iron --reinstall-packages-from=current`.
Global package migration between versions
When installing a new Node.js version, pass `--reinstall-packages-from=<version>` to carry global npm packages forward. This preserves globally installed tools like eslint or tsx without manually reinstalling each one after a version switch.
Docker and CI/CD compatibility
Use nvm inside Docker containers and CI jobs by setting the `BASH_ENV` variable so nvm loads in non-interactive shells. The README includes Dockerfile examples for both interactive and CI-style container setups, including an Ubuntu-based CI pattern that works across interactive and non-interactive containers.
Strengths and trade-offs#
Strengths
- Per-user install, no root access requirednvm installs entirely under `~/.nvm` in user space with no sudo, no system-directory writes, and no risk of breaking other users' Node installations on a shared server. This makes it safe on shared hosting environments and developer machines where system Node was installed separately.
- 95,469 GitHub stars and maintained since 2010nvm has been actively maintained since April 2010 and reached 95,469 GitHub stars, making it the most widely adopted Node.js version manager. The project follows CII Best Practices, has an active test suite, and received its last push in October 2026. Community documentation covers edge cases on macOS, Alpine Linux, FreeBSD, and Windows WSL.
- MIT license with no commercial restrictionsThe MIT license imposes no restrictions on commercial use, forking, or modification. Teams can include nvm in proprietary build pipelines, corporate CI environments, and commercial hosting setups without attribution requirements beyond the license notice.
- Works with any POSIX-compliant shellnvm runs on bash, dash, ksh, zsh, and sh. It requires no architecture-specific binary download; the same install script works on x86 Linux, Apple Silicon Macs (with native arm64 Node support since v16), and ARM servers. Alpine Linux has documented workarounds in the README.
Trade-offs
- -Shell startup time overheadBecause nvm is a sourced shell function rather than a binary, sourcing it on every new shell invocation adds a small but measurable delay to terminal startup. On slower machines or shells that source many plugins, this becomes noticeable. Alternatives like fnm or Volta use compiled binaries with sub-millisecond startup overhead.
- -No native Fish shell supportnvm does not support the Fish shell. Fish users must choose from community-maintained wrappers (bass, plugin-nvm, nvm.fish, fish-nvm) that replicate the functionality, none of which are officially supported or developed by the nvm project.
- -Per-user only, not per-systemnvm is installed per-user, so different system users have separate nvm installations and separate Node.js versions. If a deployment workflow runs Node.js services as a different system user than the one who installed nvm, you need to install nvm again for that user or use a different version management approach.
Nvm vs alternatives#
nvm vs Volta
Both nvm and Volta manage Node.js versions, but they use different models. nvm activates a Node.js version per shell session via a sourced function. Volta pins versions per project in package.json using a volta key, so the correct Node.js version follows the project regardless of which shell or directory you are in.
| Feature | nvm | Volta |
|---|---|---|
| Version pinning | .nvmrc per project | package.json volta key |
| Shell activation | Per shell session (nvm use) | Automatic on command run |
| Install method | Bash script, user-space | Compiled binary |
| Shell startup overhead | Moderate (sourced function) | Low (binary shim) |
| License | MIT | Apache 2.0 |
| Fish shell support | No (community wrappers) | Yes |
nvm is the better choice when you want the widest shell compatibility, the most documented edge cases, and a zero-binary setup that works on any POSIX system without architecture-specific downloads. Volta is better when you want version pinning to live in package.json alongside the project and prefer not to run nvm use commands manually.
nvm vs fnm
fnm (Fast Node Manager) is a compiled Rust binary that implements a compatible .nvmrc workflow to nvm but with significantly lower shell startup overhead. On machines running shells with many plugins, the startup time difference is noticeable.
| Feature | nvm | fnm |
|---|---|---|
| Startup overhead | Moderate (shell function) | Low (compiled binary) |
| .nvmrc compatibility | Yes | Yes |
| Language | Shell (bash) | Rust |
| License | MIT | MIT |
fnm is worth considering when shell startup time is a priority and you do not need nvm's broader shell compatibility, CI/CD documentation, or Alpine and FreeBSD coverage. nvm is the safer choice for teams that need documentation on platform-specific edge cases or are deploying on less common systems.
Quick start#
Install nvm via the official curl script, which clones the repository to ~/.nvm and updates your shell profile.
```bash
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.8/install.sh | bash
```What it's built on#
- Runtimes
- Node.js
FAQ#
Is nvm free to use for commercial projects?
Yes. nvm is MIT licensed, which means it can be used freely in commercial and proprietary projects with no restrictions beyond retaining the copyright notice. There is no paid tier, no usage limit, and no vendor agreement required.
How do I install a specific Node.js version with nvm?
Run nvm install <version> where version is a version number (e.g., nvm install 20), a named alias (nvm install lts/iron), or --lts for the latest Long-Term Support release. After installing, activate it in the current shell with nvm use <version>. Set a persistent default for new shells with nvm alias default <version>.
Does nvm work on Windows?
nvm-sh/nvm works on Windows through WSL (Windows Subsystem for Linux) and Git Bash/MSYS/Cygwin. Native Windows users without WSL should use nvm-windows (a separate, unrelated project) instead. The two projects share a name concept but have different codebases, and the nvm-sh team does not maintain nvm-windows.
What is the .nvmrc file and how does it work?
A .nvmrc file placed in a project directory contains a Node.js version number or alias such as 20 or lts/iron. Running nvm use in that directory reads the file and switches to the specified version. Shell hooks for bash and zsh can call nvm use automatically whenever you change directories, so the switch happens without any manual command.
How does nvm compare to Volta or fnm?
nvm is a POSIX shell function that activates a Node.js version per shell session. Volta and fnm are compiled binaries with lower shell startup overhead. Volta pins Node versions per-project in package.json rather than a separate .nvmrc file and supports Fish shell natively. fnm supports .nvmrc files like nvm but is written in Rust. nvm has the broadest adoption (95,469 GitHub stars), the most documented platform edge cases, and the longest community history since 2010.
Similar open-source tools#
Termux App
Linux terminal and package manager for Android devices.
Rust
Systems language with memory safety and no garbage collector.
Arrmada
Movies, TV, books and requests in one app, arr stack included
Simutil
Launch, manage, and stream Android emulators and iOS simulators.
FckSignups
Open-source tools that work instantly, no signup required
DeepSeek TUI
A coding agent that lives in your terminal.

