Skip to content
Latchkey

nvm: Fix "command not found" in CI Shells

nvm is defined as a shell function by nvm.sh, so it lives in no binary on PATH; CI shells must source nvm.sh before any nvm call.

The single most common nvm-in-CI failure is "command not found", and it is never a broken install. It is that the job shell never ran the init script that defines the function.

What it does

The nvm installer appends export NVM_DIR=...; [ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" to your ~/.bashrc or ~/.bash_profile. Interactive login shells read those files; the bare bash shells CI uses for each step do not, so the function is undefined.

Common usage

.github/workflows/ci.yml
- name: Use nvm
  shell: bash
  run: |
    export NVM_DIR="$HOME/.nvm"
    . "$NVM_DIR/nvm.sh"
    nvm install 20
    nvm use 20
    node -v
# alternative: a login shell that sources the profile itself
- run: nvm use 20 && node -v
  shell: bash -l {0}

Options

ApproachWhat it does
. "$NVM_DIR/nvm.sh"Source the function definition in this step
shell: bash -l {0}Run a login shell so it reads ~/.bash_profile
nvm.sh --no-useSource nvm without selecting a version (faster)
$NVM_DIR/nvm-execA wrapper script that loads nvm then runs a command

In CI

Each GitHub Actions run: block is a separate shell, so sourcing in one step does not carry to the next. Either source nvm.sh in every step, or prefer the actions/setup-node action when you do not specifically need nvm. Sourcing must happen before the first nvm call in each step.

Common errors in CI

"nvm: command not found": source nvm.sh first. "/usr/bin/env: bash: No such file" when using bash -l {0} on an image without a login profile means there is no profile to load; fall back to explicit sourcing. If nvm use runs but node -v is wrong in a later step, remember PATH changes do not persist across steps.

Related guides

Run this faster and cheaper on Latchkey managed runners. Start free →