#1643·husky

Docs: init.sh nvm example only solves PATH, not shell function availability in hook subprocesses

Author: arsdehnelCreated Jul 1, 2026Updated Jul 1, 2026

Problem

The nvm how-to docs recommend placing nvm initialisation in ~/.config/husky/init.sh to fix nvm: command not found. The example given:

bash
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"

This only partially solves the problem. It fixes the PATH issue for GUI apps (VS Code, Tower, etc.) that launch hooks with a minimal environment. However, it does not make the nvm shell function available inside hook scripts.

Why

Looking at the husky shell wrapper (node_modules/husky/husky):

bash
i="${XDG_CONFIG_HOME:-$HOME/.config}/husky/init.sh"
[ -f "$i" ] && . "$i"   # nvm function defined HERE in this shell

sh -e "$s" "$@"          # hook runs in a NEW subprocess

init.sh is sourced in the husky wrapper process. The hook script is then executed via sh -e, which spawns a subprocess. Environment variables (like PATH) are inherited by subprocesses — which is why the PATH fix works. Shell functions are not inherited, so the nvm function is unavailable inside the hook even after init.sh runs correctly.

This can be confirmed: after following the docs, the PATH in the hook error output will already contain the nvm node directory (proving init.sh ran and set PATH), yet nvm: command not found still occurs if the hook calls nvm directly.

Workaround

Source nvm directly inside the hook file:

bash
export NVM_DIR="${NVM_DIR:-$HOME/.nvm}"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" && nvm install && nvm use
pnpm install

This works for both GUI apps (no PATH issue) and terminal users (nvm function available). The init.sh approach is not needed alongside this.

An alternative that avoids touching hook files is to put nvm use in init.sh itself (after sourcing nvm.sh), since the function IS available there. This sets PATH correctly before the subprocess starts, so the hook gets the right node without needing to call nvm directly. But this approach is not obvious from the docs.

Suggestion

The docs should clarify:

  1. What init.sh actually solves (PATH inheritance for GUI apps)
  2. That calling nvm directly from within a hook requires sourcing nvm.sh inside the hook itself, or running nvm use from init.sh before the subprocess starts
  3. The distinction between environment variables (inherited by subprocesses) and shell functions (not inherited)

Related closed issue with the same root cause but no docs fix: #1579