nvm: Node versions and shell state
Deploying nvm in teams and CI: shell initialization is part of the build
Plan manager pinning, profile ownership and noninteractive initialization without mistaking an interactive terminal for a reproducible CI environment.
What you will learn
- Define what the installation may change
- Noninteractive jobs need explicit initialization
- Production process startup is another boundary
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
- Suppressing profile edits does not suppress installation writes.
- Every noninteractive shell needs an intentional initialization path.
- Service startup must verify the runtime under the actual service identity.
Define what the installation may change
The inspected install.sh selects a destination, fetches manager files and detects a profile to receive loading snippets. PROFILE=/dev/null disables that profile-editing step; it does not turn installation into a read-only operation. A team rollout should record manager revision, destination, intended profile and whether any requested Node version will also be installed.
Review the downloaded installer before executing it, and keep its source identity with the rollout record. Do not mix manual and installer-managed loading lines without checking for duplicates. A wrong profile or an uninitialized shell explains many command-not-found reports; repeatedly downloading the same installer is not a substitute for diagnosing which file the shell actually reads.
Noninteractive jobs need explicit initialization
A CI step is not necessarily the same kind of shell as the developer terminal. The README discusses explicit sourcing and Bash BASH_ENV integration for noninteractive use. Choose one deliberate initialization mechanism and test it in the actual runner. A variable named NVM_DIR alone does not define the nvm function or select a Node executable.
Pin the manager and runtime separately, and make the effective runtime visible in job logs without printing secrets. If each CI step starts a fresh shell, a version selected in one step does not automatically become another step’s shell state. A wrapper that initializes and selects before executing the build can make this boundary explicit.
Production process startup is another boundary
nvm-exec loads nvm with --no-use, selects through NODE_VERSION or the project lookup path, then uses exec to run the requested command. This explains the intended child-process boundary, but the script was inspected rather than exercised here. Production service users, permissions, executable paths and restart behavior still require environment-specific verification.
Treat runtime upgrades as application changes with acceptance tests and rollback plans. A version directory surviving on disk does not prove that a service can use it or that dependencies are compatible. This article provides a rollout checklist, not a claim that a container image, CI job or production service has been built and deployed successfully.
Implementation steps
- 1
Record manager pin, runtime pin, destination and profile owner.
- 2
Review the installer and approve its intended writes.
- 3
Test initialization in a fresh noninteractive runner shell.
- 4
Verify the built application and document rollback before changing services.
Copy-ready example
# CI wrapper fragment: nvm and this runtime must already be installed
# NVM_DIR must be supplied by the approved runner configuration
. "$NVM_DIR/nvm.sh" --no-use || exit 1
nvm use 24.14.0 || exit 1
nvm which current
node --version
# Run the project-specific build only after these checks passFrequently asked questions
Does PROFILE=/dev/null mean nothing is installed?
No. It suppresses profile editing, while manager download and other installation behavior remain separate actions.
Why did nvm disappear in the next CI step?
That step may start a fresh shell without initialization. Test the runner’s real process boundaries rather than relying on a previous interactive shell.
Sources
- README.mdSource checked 2026-09-08
- install.shSource checked 2026-09-08
- nvm-execSource checked 2026-09-08