nvm: Node versions and shell state
Inside nvm: installed versions, shell state and child execution
Trace the distinction between stored Node versions, selectors, PATH changes and the process created by an explicit nvm exec command.
What you will learn
- Storage and selection are different layers
- The use branch updates the calling shell
- An explicit child command has a bounded lifetime
Before you start
- Basic shell commands and process environments
- Distinguish runtime installation from runtime selection
Diagnose requested versus active Node versions and design explicit setup and verification boundaries.
Key takeaways
- Stored version, selector and active process are distinct states.
- A shell function can update the environment that launches the next process.
- Helper correctness does not validate the whole installation and execution lifecycle.
Storage and selection are different layers
nvm maintains version directories and supporting alias and cache state beneath its chosen directory. A selector such as an exact version, default or current must be interpreted before a command can decide what to run. The .nvmrc parser returns text; resolving that text to a known, installed runtime is a later responsibility.
This separation explains why a parsed request can still fail during selection. It also explains why changing a default alias is different from immediately changing every active shell. Inspect stored versions, the selector that was used and the active process separately instead of treating all three as one global version variable.
The use branch updates the calling shell
After checking the selected version, the inspected use branch computes its version directory and calls nvm_change_path. It exports PATH, updates relevant manual-page state, resets the shell command cache and sets NVM_BIN and NVM_INC. This is why nvm is loaded as a shell function: a separate ordinary executable could not directly rewrite its parent shell environment.
The optional NVM_SYMLINK_CURRENT path has an additional filesystem side effect, replacing a current link. That is not required to explain ordinary per-shell selection and should not be silently enabled in a tutorial. The helper probe passed literal strings to the PATH functions and did not enter this full environment-changing use branch.
An explicit child command has a bounded lifetime
The small nvm-exec script sources the manager without automatic use, selects a version, then replaces itself with the requested command using exec. An explicit version makes the intended runtime easier to reason about than an omitted selector whose fallback depends on current state. Process startup remains distinct from installing a distribution or modifying a profile.
The experiment covers extracted text-processing helpers, not every caller, shell or process lifecycle. It demonstrates useful seams for testing: PATH transformation and .nvmrc content parsing can be observed independently from downloads, filesystem layout and application execution. Integration tests must reconnect those seams before declaring an actual rollout successful.
Implementation steps
- 1
Identify where a selector comes from.
- 2
Trace resolution to an installed version directory.
- 3
Follow environment changes in the use branch.
- 4
Verify the command launched under that environment separately.
Copy-ready example
selector / .nvmrc -> version resolution -> installed directory
|
calling shell <- PATH + NVM_BIN + NVM_INC <- use
|
+-> newly launched Node process
existing processes: unchangedFrequently asked questions
Why is nvm normally sourced rather than executed?
It defines shell functions that can change the calling shell’s environment. An ordinary child executable cannot directly change its parent’s PATH.
Did the helper probe run nvm use?
No. It executed selected source functions with literal inputs, not the full command branch that exports environment variables and may update state.