NVM (Node Version Manager) β Core Functionality#
Overview#
NVM is a POSIX-compliant shell function (not a binary) for managing multiple active Node.js versions per user, per shell. It supports sh, dash, bash, ksh, and zsh . The entire implementation lives in a single sourced file β no compiled code involved.
Key files:
| File | Role |
|---|---|
nvm.sh | All shell functions; sourced at startup |
README.md | Install snippets, .nvmrc format docs, shell integration recipes |
Shell Startup Initialization#
Profile snippet#
The installer adds the following to ~/.bashrc, ~/.bash_profile, ~/.zshrc, or ~/.profile :
export NVM_DIR="$([ -z "${XDG_CONFIG_HOME-}" ] && printf %s "${HOME}/.nvm" || printf %s "${XDG_CONFIG_HOME}/nvm")"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm
Pass --no-use as an argument to suppress automatic version activation . If $XDG_CONFIG_HOME is set, nvm files are placed there instead of ~/.nvm .
Auto-mode: nvm_process_parameters β nvm_auto#
At the very end of nvm.sh, nvm_process_parameters "$@" runs unconditionally on every source . It parses the startup flags and calls nvm_auto with one of three modes:
| Mode | Trigger | Behavior |
|---|---|---|
none | --no-use | Exit immediately; no version activated |
use | (default) | Activates the default alias, or falls back to .nvmrc if no version is active |
install | --install | Installs the default alias version, or reads .nvmrc |
NVM_DIR is auto-detected at startup by using nvm_cd ${NVM_CD_FLAGS} to resolve the script's own directory β NVM_CD_FLAGS is set for zsh compatibility (see below).
.nvmrc File Parsing#
Discovery#
nvm_find_nvmrc delegates to nvm_find_up '.nvmrc', which walks up $PWD one directory at a time until it finds the file or reaches the root . This means any subdirectory of a project with .nvmrc will inherit it .
File format#
.nvmrc must contain exactly one nvm-recognized version string (e.g., 5.9, lts/*, node) followed by a newline . Format rules :
#starts a comment; everything after it on a line is ignored.- Blank lines and leading/trailing whitespace are ignored.
key=valuepairs are allowed (silently skipped; reserved for future use).- Multiple bare version strings are invalid.
Run npx nvmrc to validate a .nvmrc file .
Parsing: nvm_process_nvmrc_content#
nvm_process_nvmrc_content performs these steps:
sed 's/#.*//'strips comments; anothersedpass trims whitespace; blank lines are filtered out .- Each remaining line is classified: bare version string vs.
key=valuepair. Duplicate keys, multiple bare strings, or lines starting with=(missing key) cause validation failure . - On success, the single bare version string is echoed to stdout. On failure,
nvm_nvmrc_invalid_msgprints a diagnostic and returns 1.
nvm_rc_version is the public entry point: it orchestrates discovery β parsing and writes the resolved version to fd 3. Callers (e.g., nvm use) capture it with the idiom { version="$(nvm_rc_version 3>&1 1>&4)"; } 4>&1.
zsh extendedglob Compatibility#
NVM uses several techniques to prevent zsh's stricter glob handling from causing failures.
NVM_CD_FLAGS=-q#
On startup, when zsh is detected via nvm_is_zsh, NVM_CD_FLAGS is set to -q . The -q flag quiets zsh's "no matches found" error that arises from extendedglob/nomatch when a glob pattern in a cd path goes unmatched. The nvm_cd wrapper always passes $NVM_CD_FLAGS to \cd.
setopt local_options guards#
Changes to zsh shell options are scoped with nvm_is_zsh && setopt local_options β¦ so they don't leak out of the calling function. Key sites:
| Option | Location | Purpose |
|---|---|---|
shwordsplit | nvm_install_source, nvm run | Enables POSIX word-splitting so $ADDITIONAL_PARAMETERS expands correctly |
nonomatch | nvm_check_file_permissions | Suppresses "no matches found" when globbing directory entries (*, .[!.]*, ..?*) |
unsetopt markdirs | alias listing | Disables automatic / suffix appended to directory names during glob expansion |
ERR_RETURN in subshells#
nvm_has_executable runs in a subshell and uses || true on unalias and unset -f calls specifically because zsh's ERR_RETURN option would abort the subshell on a non-zero exit from those builtins.
Source builds on old Node (< 0.12)#
When compiling Node from source for versions before 0.12, SHELL=/bin/sh is injected into the make invocation to prevent zsh's strict glob handling from interfering with unquoted glob patterns in Node's Makefiles .
Key Environment Variables#
| Variable | Default | Purpose |
|---|---|---|
NVM_DIR | ~/.nvm (or $XDG_CONFIG_HOME/nvm) | NVM root directory |
NVM_CD_FLAGS | "" (zsh: "-q") | Flags passed to \cd; -q suppresses zsh glob errors |
NVM_SILENT | 0 | Suppress output when set to 1 |
NVM_NO_COLORS | unset | Disable ANSI color output |
NVM_SYMLINK_CURRENT | unset | Create $NVM_DIR/current symlink on nvm use |
NVM_AUTH_HEADER | unset | Authorization header forwarded to download mirror |
Call Chain: nvm use (no version argument)#
nvm use
β nvm_rc_version # (cite:github_file:b0c49709:631-653)
β nvm_find_nvmrc # walks up $PWD for .nvmrc
β nvm_find_up '.nvmrc' # (cite:github_file:b0c49709:521-533)
β nvm_process_nvmrc # reads file content
β nvm_process_nvmrc_content # strips comments, validates, returns version
β nvm_version "${provided_version}"
β nvm_change_path / export PATH
The same .nvmrc lookup (nvm_rc_version) is used by nvm install, nvm which, nvm run, nvm exec, and nvm_auto during shell startup.
Deeper shell integration: For automatic per-directory switching (e.g.,
nvm useon everycd), see the bash and zsh hook recipes in README.md.