41

Let's say I have 2 projects:

example1: requires node version 0.12.1
example2: requires node version 0.10

Currently, when I cd into each project, I use nvm use <version> before running the application.

Is there a way with node or nvm, to automatically switch to the needed version of node when I cd into each project?

cusejuice
  • 10,285
  • 26
  • 90
  • 145

10 Answers10

31

Looks for a .nvmrc file in your current directory, every time you cd. If one is found, it loads the version via nvm use and throws out any output.

cd() {
  builtin cd "$@"
  if [[ -f .nvmrc ]]; then
    nvm use > /dev/null
  fi
}
cd .
mcnelson
  • 319
  • 3
  • 2
  • Nice and easy, the best of all. Thanks – Nafaa Boutefer Nov 12 '20 at 08:37
  • 5
    Note that the code snippet that is provided in the answer should be placed in the `~/.zshrc` file if you are using ZSH terminal. And the `.nvmrc` file should be placed in the root of your project directory. Also, the content that you need to add to the `.nvmrc` is the Node version that you want to use (like: `v14.21.1` for example). – Amr Nov 23 '22 at 15:22
  • Seems like you don't have to do this anymore. nvm will auto switch the node version in your directory if it finds a `.nvrmc` file. Doing `node -v > .nvmrc` will create one with a current node version in your project. – sjsupersumit Jun 09 '23 at 16:27
17

Install Automatic Node Version Switching (avn) and add .node-version file that specifies the version you'd like to use with project. It automatically detects and uses it via installed version manager such as nvm and n.

ferhatelmas
  • 3,818
  • 1
  • 21
  • 25
  • 3
    This project's owner is no longer maintaining avn and so this solution will not work on Ubuntu; you will get an error when you attempt to set it up. – kozan Dec 07 '21 at 20:37
  • 1
    Same on mac by the look of it, however @illnr solution for zsh works great. – Robin Goupil Apr 01 '22 at 09:28
15

You can add nvm command into package.json file

"scripts": {
  "preinstall": "nvm install 0.12.1",
  "prestart": "nvm use 0.12.1",
  "start": "node ./file1.js"
},

Also set desired version into package.json, so Continuous Integration services would know what version you want to use.

{
  "name": "naive",
  "description": "A package using naive versioning",
  "author": "A confused individual <iam@confused.com>",
  "dependencies": {
    "express": ">= 1.2.0",
    "optimist": ">= 0.1.0"
  },
  "engine": "node 0.4.1"
}
vromanch
  • 939
  • 10
  • 22
  • 11
    When I run `npm install` it fails to run the first command and says `nvm command not found`. `nvm` is installed and I can run the command from shell. – ajay Oct 05 '16 at 07:59
  • 1
    I have the same issue that @ajay has reported above – JamieJag Dec 01 '16 at 11:21
  • @ajay You need to execute `nvm.sh` file first. Example `sh ~/.nvm/nvm.sh && nvm use 14.15.4`. – Laode Muhammad Al Fatih Jan 11 '21 at 01:33
  • This is not working for me. Not even Laode's suggestion. I am using .zshrc and macosx but need it to be cross platform. Console prints following: `> sh ~/.nvm/nvm.sh && nvm use 12.18.3 sh: nvm: command not found` – prius Oct 25 '21 at 12:48
  • If you still have problems running nvm, add the scripts like this `"preinstall": ". ~/.nvm/nvm.sh && nvm install 0.12.1",` `"predev": ". ~/.nvm/nvm.sh && nvm use 0.12.1",` – iusting Mar 06 '23 at 10:18
11

There are also extended (user contributed) bash/zsh shell scripts in the NVM GitHub README:

bash script

Automatically call nvm use
This alias would search 'up' from your current directory in order to detect a .nvmrc file. If it finds it, it will switch to that version; if not, it will use the default version.

Put the following at the end of your $HOME/.bashrc:

find-up () {
    path=$(pwd)
    while [[ "$path" != "" && ! -e "$path/$1" ]]; do
        path=${path%/*}
    done
    echo "$path"
}

cdnvm(){
    cd "$@";
    nvm_path=$(find-up .nvmrc | tr -d '[:space:]')

    # If there are no .nvmrc file, use the default nvm version
    if [[ ! $nvm_path = *[^[:space:]]* ]]; then

        declare default_version;
        default_version=$(nvm version default);

        # If there is no default version, set it to `node`
        # This will use the latest version on your machine
        if [[ $default_version == "N/A" ]]; then
            nvm alias default node;
            default_version=$(nvm version default);
        fi

        # If the current version is not the default version, set it to use the default version
        if [[ $(nvm current) != "$default_version" ]]; then
            nvm use default;
        fi

        elif [[ -s $nvm_path/.nvmrc && -r $nvm_path/.nvmrc ]]; then
        declare nvm_version
        nvm_version=$(<"$nvm_path"/.nvmrc)

        declare locally_resolved_nvm_version
        # `nvm ls` will check all locally-available versions
        # If there are multiple matching versions, take the latest one
        # Remove the `->` and `*` characters and spaces
        # `locally_resolved_nvm_version` will be `N/A` if no local versions are found
        locally_resolved_nvm_version=$(nvm ls --no-colors "$nvm_version" | tail -1 | tr -d '\->*' | tr -d '[:space:]')

        # If it is not already installed, install it
        # `nvm install` will implicitly use the newly-installed version
        if [[ "$locally_resolved_nvm_version" == "N/A" ]]; then
            nvm install "$nvm_version";
        elif [[ $(nvm current) != "$locally_resolved_nvm_version" ]]; then
            nvm use "$nvm_version";
        fi
    fi
}
alias cd='cdnvm'

zsh script

Calling nvm use automatically in a directory with a .nvmrc file
Put this into your $HOME/.zshrc to call nvm use automatically whenever you enter a directory that contains an .nvmrc file with a string telling nvm which node to use:

# place this after nvm initialization!
autoload -U add-zsh-hook
load-nvmrc() {
  local node_version="$(nvm version)"
  local nvmrc_path="$(nvm_find_nvmrc)"

  if [ -n "$nvmrc_path" ]; then
    local nvmrc_node_version=$(nvm version "$(cat "${nvmrc_path}")")

    if [ "$nvmrc_node_version" = "N/A" ]; then
      nvm install
    elif [ "$nvmrc_node_version" != "$node_version" ]; then
      nvm use
    fi
  elif [ "$node_version" != "$(nvm version default)" ]; then
    echo "Reverting to nvm default version"
    nvm use default
  fi
}
add-zsh-hook chpwd load-nvmrc
load-nvmrc
illnr
  • 750
  • 9
  • 13
  • Hi, @illnr thanks it worked. Can you please tell why do i need First line -> autoload -U add-zsh-hoo, Lastline -> add-zsh-hook chpwd load-nvmrc it is working fine for me just load-nvmrc function and invoking it only. – khizer Jun 02 '22 at 06:04
  • I think this should be the best solution. – Will Oct 18 '22 at 13:23
4

NPM now let's you specify the node version for a project like this npm install node@8.

So next time you do a npm ci or npm i, the correct version is automatically set.

siwalikm
  • 1,792
  • 2
  • 16
  • 20
  • That didn't work for me. npm -v says the wrong version when I go inside my project. I have to use nvm use {nodeversion} still and it switches node/npm. We have engines section which disallows the wrong usage. – Dean Hiller Feb 15 '22 at 01:28
1

If you're using ubuntu try below,

 "scripts": {
  "prestart": ". ~/.nvm/nvm.sh && nvm use",
   ...
}

if you have created .nvmrc file then you don't need to specify version.

Asad Jivani
  • 535
  • 1
  • 5
  • 15
0

If you're using a Bash shell, you can define a Bash alias to cd, which will do nvm install / nvm use for you when it detects a .nvmrc file.

alias cd='function cdnvm(){ cd $@; if [[ -f .nvmrc ]]; then <.nvmrc nvm install; fi; };cdnvm'

If you want to make the Node version to revert back to the default when you cd out of the directory, use the following alias:

alias cd='function cdnvm(){ cd $@; if [[ -f .nvmrc && -s .nvmrc  && -r .nvmrc ]]; then <.nvmrc nvm install; elif [[ $(nvm current) != $(nvm version default) ]]; then nvm use default; fi; };cdnvm'
d4nyll
  • 11,811
  • 6
  • 54
  • 68
0

If you're fine with using another tool you could use nvshim.

pip install nvshim  # this is all you need to do

It does not slow your shell start up, instead moving the lookup of which node version to when you call node, npm or npx by shimming those binaries. More details in the docs.

Source, I wrote the tool.

iamogbz
  • 99
  • 1
  • 13
  • this messed with my pm2 installation on ubuntu server 20, and also does some pretty weird stuff on my development machine.. It tries to find a 'default' version but cannot find it, even though the default is aliased with nvm correctly.. Uninstalled after 2 days of trying to fix this issue... – Unispaw Mar 23 '22 at 07:55
  • @Unispaw thanks for the feedback! Should be addressed in [v1.1.2](https://github.com/iamogbz/nvshim/issues/171#issuecomment-1078719002) – iamogbz Jun 28 '23 at 12:32
0

This is what I'm currently using to autoload the node version per project. It updates a variable for use when node is invoked. It prevents switching node versions for every dir change.

https://gist.github.com/ryanpback/1d0b2808f896398eab6106f49b3e99ab

ryanpback
  • 275
  • 4
  • 17
-1

I think the best solution and totally angnostic is to install Directory Enviroment (direnv), an extension for your shell. It augments existing shells with a new feature that can load and unload environment variables depending on the current directory.

If you use bash as shell add the following line at the end of the ~/.bashrc file:

eval "$(direnv hook bash)"

Instead if you use another shell, simply follow the instructions at this linkenter link description here

Then you must add .envrc file inside your project and specifies the version you'd like to use:

use nodejs 16

After thease steps, it will automatically detects and uses the specified version.

kreo
  • 1