18

In ruby when using rbenv you can make a .ruby-version file and put it in the local directory. https://gist.github.com/fnichol/1912050 I'm looking for something similar to this using NVM?

Question:

Is there a property to set in package.json or a file to create that will set the default version of node of a project?

Armeen Moon
  • 18,061
  • 35
  • 120
  • 233

4 Answers4

32

You can do this with a combination of NVM, dotfiles in your project directory, and a little tool called direnv which allows you to load in environment variables on a per-directory basis.

http://direnv.net/

Install NVM and direnv, and then cd to the directory you want to change Node versions in.

Add a file called .nvmrc in that directory, containing just the version number of the Node version you want to auto-switch to, e.g.,:

6.2.2

Then add an environment configuration file called .envrc to your directory, containing this script:

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

PATH_add node_modules/.bin

If you now cd out of this directory, and then cd back in, direnv will kick in and you should be asked to add the directory to your direnv whitelist by typing direnv allow . at the prompt. Once whitelisted, direnv will auto-run that script whenever you enter this directory, setting your Node version to the version number in .nvmrc.

As a bonus, it will also add the node_modules directory to your PATH, so you can execute binaries from those directories without prepending the node_modules path.

Ross Shannon
  • 548
  • 6
  • 7
  • 1
    The great thing about direnv is that it automatically undoes all its modifications when you change out of the directory (eg: to a different project). This answer doesn't support undoing the effect of `nvm use` when direnv unloads. – Tyson Mar 27 '18 at 22:48
  • To add to Ross' answer, you can use `asdf` instead of `nvm` which works very similar to nvm but does more than just nodejs. See [asdf-nodejs](https://github.com/asdf-vm/asdf-nodejs) and [asdf-vm](https://github.com/asdf-vm) The combination of `asdf` and `direnv` works magic – Pieter Venter Aug 12 '19 at 03:26
  • `node -v > .nvmrc` will create the file in one go – DigitalDesignDj May 19 '20 at 15:50
8

There is now some native support for this built into direnv's stdlib. It's documented in their wiki, but the source is just as easy to read, or type direnv stdlib to find it).

$ node -v
v8.0.0
$ cat .node-version
4.3.2
$ cat .envrc
use node
$ export NODE_VERSIONS=~/.nvm/versions/node
$ export NODE_VERSION_PREFIX=v
$ direnv allow
direnv: loading ~/.config/direnv/direnvrc
direnv: loading .envrc
direnv: using node
direnv: Successfully loaded NodeJS v4.3.2 (via .node-version), from prefix (~/.nvm/versions/node/v4.3.2)
direnv: export +CPATH +LD_LIBRARY_PATH +LIBRARY_PATH +PKG_CONFIG_PATH ~MANPATH ~PATH
$ node -v
v4.3.2
$ direnv deny
direnv: error .envrc is blocked. Run `direnv allow` to approve its content.
$ node -v
v8.0.0

If you want node_modules/.bin in your path, just add the line layout node to your .envrc (the source is also in direnv stdlib output).

deizel.
  • 11,042
  • 1
  • 39
  • 50
7

Here's how I do it, generally similar to Ross Shannon's answer, with a few differences:

  1. You can specify the Node version in just the package.json, without requiring an .nvmrc file
  2. You can also specify the Node version directly in the .envrc, again without an .nvmrc file
  3. I don't add node_modules/.bin to the PATH, but if that's your preferred behavior, just add PATH_add node_modules/.bin to the use_nvm function.

For me, supporting Node version selection from package.json rather than .nvmrc was important because I didn't want to worry about keeping two files in sync (especially on a project with multiple collaborators). That said, this solution still works with .nvmrc.

This solution requires direnv, nvm and optionally (if you want to be able to select the Node version from package.json) jq.

In ~/.config/direnv/direnvrc file, add the following:

# To use:
# 1) Node version specified in package.json, in .envrc add:
#      use nvm package.json
#    This requires that package.json contains something like
#      "engines": {
#        "node": ">=6.9.2"
#      },
#
# 2) Node version specified in .envrc add:
#      use nvm 6.9.2
#
# 3) Node version specified in .nvmrc, in .envrc add:
#      use nvm
use_nvm() {
  local node_version=$1

  if [[ $node_version = "package.json" ]]; then
    if has jq; then
      node_version=$(jq --raw-output .engines.node package.json | tr -d "<=> ")
    else
      echo "Parsing package.json for node version to use with direnv requires jq"
    fi
  fi

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

In your project directory, add an .envrc file that calls use nvm, e.g.:

use nvm package.json

However, I prefer something like the following for my .envrc:

if declare -Ff use_nvm >/dev/null; then
  use nvm package.json
fi

for shared projects with a shared .envrc so that collaborators who don't have use nvm defined don't get an error.

Now, when you enter your project directory, your desired Node version will be automatically used (the first time, you'll be prompted to whitelist your changes to .envrc with direnv allow).

eddies
  • 7,113
  • 3
  • 36
  • 39
  • Thank you lots for the answer, this is perfect! I use nvm and I couldn't bother setting up a different default node version for my whole system, but when I need to run something most of the time I need a newer version of node than my system's, so I simply decided to use a `.envrc` in my home folder, but then no nvm integration, until I found this. Now I can just put `use nvm default` in my `~/.envrc` and I have automatic node version when I need :) Thanks! – Karrq Jun 13 '23 at 15:19
1

Note: This solution does not switch the folder version automatically.

Other answers were not that helpful to me, and hence, this is the solution I followed:

Create a .nvmrc file and specify the node version you expect your app to run on.

touch .nvmrc

Open the file and specify the version, say 13.3.0

Post you define a version in .nvmrc, you can alternatively also define the engines in the package.json file, which will ensure that the version meets the requirements, if it doesn't, running npm install will fail.

"engineStrict": true,
"engines": {
  "node": "13.3.0"
}

Below is the error you'll encounter if it fails to match the node version.

Source: My Project

Lastly, to ensure that it switches to the right node version, you can either run the following command post navigating to the directory.

nvm use

And this will switch to the desired version, or you can add it to one of the script command in package.json like:

"scripts": { 
  /*
   * here, the second command (nodemon server.js) will change base on the dev 
   * server you are using and the path where you've server.js
  */
  "dev:app:run": "nvm use; nodemon server.js"
},

The above will switch the node version before it starts the server.

Mr. Alien
  • 153,751
  • 34
  • 298
  • 278