Skip to content
Austin Ziegler edited this page Jan 31, 2023 · 31 revisions

Installing a Node.js version to a directory

locate the desired Node.js version
curl -s https://nodejs.org/dist/index.tab | awk '/^v[0-9]/{ print $1 }' | less
create version directory
mkdir -p $NODE_VERSIONS/node-v8.9.4
download for Mac OS X or Linux

Mac OS X

curl -fsSL http:https://nodejs.org/dist/v8.9.4/node-v8.9.4-darwin-x64.tar.gz | tar xvz --strip 1 -C $NODE_VERSIONS/node-v8.9.4

Linux

curl -fsSL http:https://nodejs.org/dist/v8.9.4/node-v8.9.4-linux-x64.tar.gz | tar xvz --strip 1 -C $NODE_VERSIONS/node-v8.9.4
export path
export PATH="$NODE_VERSIONS/node-v8.9.4/bin:$PATH"

Load Node.js version from a .node-version or .nvmrc file.

Loads a Node.js version from directory prefix specified by $NODE_VERSIONS environment variable. You can further customize the sub-directory lookup via $NODE_VERSION_PREFIX.

If you specify a partial Node.js version (i.e. "8.9" or "8"), a fuzzy match is performed and the highest matching version installed is selected.

.envrc

set -e
use node

.node-version or .nvmrc

8

Load Node.js version specified in .envrc

.envrc

use node 8.9.4

Using the layout node directive

You can optionally add the layout node directive in your .envrc to have the node_modules/bin path added to the PATH (though, this is generally not recommended).

Using nvm

It's possible to use nvm to manage Node versions and direnv to load them. For this add the following in the ~/.config/direnv/direnvrc file:

use_nvm() {
  local node_version=$1

  nvm_sh=~/.nvm/nvm.sh
  if [[ -e $nvm_sh ]]; then
    source $nvm_sh
    nvm use $node_version
  fi
}

Using nvm, install a couple of versions, e.g. nvm install 10.15.3.

Then in any project's .envrc include:

use nvm 10.15.3

Using nvm with Automatic Discovery

This version of use_nvm also supports jorgebucaran/fish-nvm, a fish-specific alternative to nvm wrappers, and will read from .node-version or .nvmrc files if called with --auto. This uses functions described in Find Up with Alternates.

When using fish-nvm, the Node version must already be installed (fish-nvm normally auto-installs; because this is using infrastructure provided by fish-nvm, this does not happen).

use_nvm() {
  local version
  version="$1"

  [[ "${version}" == --auto ]] && version="$(read_version_file .node-version .nvmrc)"
  [[ -z "${version}" ]] && return

  if [[ -e ~/.nvm/nvm.sh ]]; then
    unsafe source ~/.nvm/nvm.sh
    nvm use "${version}"
  elif [[ -f ~/.local/share/nvm/.index ]]; then
    # This works with jorgebucaran/fish.nvm v2, a fish-specific alternative to
    # nvm. The version of Node requested must be installed before use.
    local -a installed
    # shellcheck disable=SC2207
    installed=($(echo ~/.local/share/nvm/* | sed -e "s!$HOME/.local/share/nvm/!!g" -e s/v//g))

    local installed_re
    installed_re="$(re_join '|' "${installed[@]}")"

    version="$(
      ruby -e \
        "puts ARGF.readlines.grep(/${installed_re}/).grep(%r{${version}}).last.split.first" \
        ~/.local/share/nvm/.index
    )"

    [[ -z "${version}" ]] && return

    if [[ -d ~/.local/share/nvm/"${version}"/bin ]]; then
      PATH_add "$(
        cd ~/.local/share/nvm || exit
        pwd -P
      )/${version}"/bin
      export NVM_BIN
      NVM_BIN=~/.local/share/nvm/"${version}"/bin
    fi
  elif [[ -f ~/.config/nvm/index ]]; then
    # This works with jorgebucaran/fish-nvm, a fish-specific alternative to
    # nvm. The version of Node requested must be installed before use.
    version="$(
      ruby -e $'
        version=ARGV.shift
        version=version.strip.gsub(/^v/, "").gsub(%r{lts/}, "lts|")
        match=ARGF.readlines.find { |l| l =~ /#{Regexp.escape(version)}/ }
        puts match.split(/\\t/).first if match
      ' "${version}" ~/.config/nvm/index
    )"

    [[ -z "${version}" ]] && return

    if [[ -d ~/.config/nvm/"${version}"/bin ]]; then
      PATH_add "$(
        cd ~/.config/nvm || exit
        pwd -P
      )/${version}"/bin
      export NVM_BIN
      NVM_BIN=~/.config/nvm/"${version}"/bin
    fi
  fi
}

This is used the same way as above (use nvm 10.15.3) or with auto-discovery (use nvm --auto).

Using auto-installing nvm

Here's yet another approach to using nvm (inspired by https://github.com/steve-ross/direnv-helpers).

Add this to ~/.config/direnv/direnvrc:

use_nvm() {
  watch_file .nvmrc
  local NVM_PATH="$HOME/.nvm/nvm.sh"
  if ! [ -f "$NVM_PATH" ]; then
    echo "Installing NVM" >&2
    curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash
  fi
  . "${NVM_PATH}"
  nvm install
  layout node
}

Now in any directory, put a Node version number like v14.15.4 in .nvmrc and put use nvm in .envrc. This will automatically install nvm in your home directory if it isn't already installed, and will automatically install whatever Node version is mentioned in .nvmrc as well. In addition, it will reload whenever you edit .nvmrc.

Use volta with Node

Volta is a Node version manager that's easy and fast to install (one small Rust binary) and lets you pin versions of npm/yarn as well as Node. Pins are stored in the volta key in your package.json and can be written with the volta pin command.

The following .envrc will automatically install volta hermetically inside your project directory.

export VOLTA_HOME="$PWD/.volta"
PATH_add "$VOLTA_HOME/bin"

if ! [ -f "$VOLTA_HOME/bin/volta" ]; then
  curl https://get.volta.sh/ | bash
fi

# Allow you to run jest and other things in node_modules/.bin without npx.
layout node

Note that if you want to support old versions of macOS you'll need to download a recent version of cacerts.pem from https://curl.se/docs/caextract.html and replace the curl line with CURL_CA_BUNDLE=.cacert.pem bash -c 'curl https://get.volta.sh/ | bash'.

source

stdlib.sh

related projects

https://github.com/steve-ross/direnv-helpers is a set of direnvrc helper functions to handle various nodejs-related scenarios