# How nvm Implements PATH Manipulation to Switch Between Node Versions

> Discover how nvm uses POSIX shell functions to manipulate the PATH environment variable, seamlessly switching Node.js versions and preserving system binary precedence. Learn the nvm PATH manipulation technique today.

- Repository: [nvm.sh/nvm](https://github.com/nvm-sh/nvm)
- Tags: internals
- Published: 2026-02-27

---

**nvm manipulates the `PATH` environment variable through three POSIX-compliant shell functions—`nvm_strip_path`, `nvm_change_path`, and the deactivate handler—that atomically rewrite path entries to point to the target Node.js version's binary directory while preserving system binary precedence.**

The Node Version Manager (nvm) enables seamless switching between Node.js installations by dynamically rewriting shell environment variables. According to the nvm-sh/nvm source code, this PATH manipulation relies on tightly-coupled helper functions defined in [`nvm.sh`](https://github.com/nvm-sh/nvm/blob/main/nvm.sh) that handle insertion, removal, and replacement of version-specific binary paths without requiring administrative privileges.

## Core PATH Manipulation Functions

### nvm_strip_path: Cleaning Existing Entries

Located at lines 982-999 of [`nvm.sh`](https://github.com/nvm-sh/nvm/blob/main/nvm.sh), the `nvm_strip_path` function removes all nvm-managed entries from a colon-separated path variable. It uses `awk` to filter out path components matching the pattern `${NVM_DIR}/*/bin` and rejoins the remaining parts. This ensures no orphaned entries persist when switching versions or deactivating.

### nvm_change_path: Surgical Path Insertion

Spanning lines 1001-1024 in [`nvm.sh`](https://github.com/nvm-sh/nvm/blob/main/nvm.sh), `nvm_change_path` handles four distinct scenarios to maintain correct path order:

1. **Empty input** – Returns the new version directory directly
2. **No existing nvm entry** – Prepends the new path to the existing variable
3. **System directories precede nvm entries** – Detects patterns like `/usr/bin` appearing before nvm paths and prepends to maintain expected precedence
4. **Existing nvm entry present** – Uses `sed` to replace the old entry in-place, avoiding duplicates

The function signature accepts the path variable, a suffix (typically `/bin`), and the target version directory.

### Deactivation and System Fallback

The `deactivate` command implementation occupies lines 1616-1652 of [`nvm.sh`](https://github.com/nvm-sh/nvm/blob/main/nvm.sh). This logic calls `nvm_strip_path` for `PATH`, `MANPATH`, and `NODE_PATH`, effectively purging all nvm-managed entries and restoring access to the system Node.js installation.

## The Version Switching Execution Flow

When a user executes `nvm use <version>`, the implementation performs these atomic operations:

1. **Resolves the target version** through alias handling or `.nvmrc` parsing
2. **Computes the installation directory** via `nvm_version_path`
3. **Rewrites PATH** using the command:
   ```bash
   PATH="$(nvm_change_path "${PATH}" "/bin" "${NVM_VERSION_DIR}")"
   export PATH
   \hash -r
   ```

   This appears at lines 5556-5568 of [`nvm.sh`](https://github.com/nvm-sh/nvm/blob/main/nvm.sh).
4. **Adjusts MANPATH and NODE_PATH** using the same helpers (lines 5560-5565)
5. **Exports auxiliary variables** `NVM_BIN` and `NVM_INC` so subprocesses like npm and node-gyp resolve the correct binaries and headers

```bash

# Switch to Node 18.17.0

$ nvm use 18.17.0
Now using node v18.17.0

# Inspect the resulting PATH

$ echo "$PATH"
/home/user/.nvm/versions/node/v18.17.0/bin:/usr/local/bin:/usr/bin:/bin

# Deactivate nvm (fall back to system Node)

$ nvm deactivate
Removed /home/user/.nvm/*/bin from $PATH

# Verify PATH restoration

$ echo "$PATH"
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

```

## Edge Cases and Precedence Handling

The implementation addresses several critical edge cases through defensive programming:

**Empty PATH variables** – When the input path is empty, `nvm_change_path` returns only the new suffix (`${NVM_VERSION_DIR}/bin`) without separators.

**System binary precedence** – The logic at lines 1014-1016 detects when system directories like `/usr/bin` or `/usr/local/bin` appear before nvm entries using the regex `(^|:)(/usr(/local)?)?${2-}:.*${NVM_DIR}/[^/]*${2-}`. In these cases, the function prepends rather than replaces, ensuring system tools maintain priority when appropriate.

**Multiple nvm entries** – The sed replacement pattern `-e "s#${NVM_DIR}/[^/]*${2-}[^:]*#${3-}${2-}#"` specifically targets only the first matching segment, protecting any later entries from corruption.

## Summary

- nvm implements PATH manipulation through three specialized functions in [`nvm.sh`](https://github.com/nvm-sh/nvm/blob/main/nvm.sh): `nvm_strip_path` (lines 982-999), `nvm_change_path` (lines 1001-1024), and the deactivate handler (lines 1616-1652)
- The `nvm_change_path` function handles four distinct scenarios: empty paths, new installations, system-prefixed paths, and in-place replacements using sed
- Version switching exports `NVM_BIN` and `NVM_INC` to ensure subprocesses resolve correct binaries and headers for native module compilation
- Deactivation completely strips nvm-managed entries using `nvm_strip_path` to restore system Node.js access
- All operations preserve POSIX compliance and handle edge cases including multiple entries and system binary precedence

## Frequently Asked Questions

### How does nvm avoid duplicate entries in PATH?

The `nvm_change_path` function checks for existing nvm-managed entries using pattern matching against `${NVM_DIR}/*/bin`. If an existing entry is detected, the function uses sed to replace the existing path segment rather than appending, ensuring only one nvm binary directory exists in PATH at any time while preserving the surrounding path structure.

### What happens to my system Node.js when I run nvm use?

The system Node.js remains installed but loses priority in the command resolution order. When you execute `nvm use <version>`, the new version's bin directory prepends to PATH, shadowing system binaries. If you need to restore exclusive system Node.js access, run `nvm deactivate`, which calls `nvm_strip_path` to purge all nvm entries and returns PATH to its pre-nvm state.

### Does nvm modify environment variables beyond PATH?

Yes. Beyond PATH manipulation, nvm updates `MANPATH` for manual pages and `NODE_PATH` for module resolution using the same `nvm_change_path` helper. It also exports `NVM_BIN` (pointing to the current version's bin directory) and `NVM_INC` (pointing to headers) to support native module compilation tools like node-gyp and make.

### Where is the PATH manipulation logic located in the nvm source code?

All PATH manipulation functions reside in [`nvm.sh`](https://github.com/nvm-sh/nvm/blob/main/nvm.sh) at the root of the nvm-sh/nvm repository. The core helpers `nvm_strip_path` and `nvm_change_path` occupy lines 982-1024, while the command implementations using these helpers appear around lines 5556-5568 for `nvm use` and lines 1616-1652 for `nvm deactivate`. The install script merely sources this file to make these functions available in the shell environment.