Nvm: .nvmrc for projects

Created on 17 Apr 2012  Â·  105Comments  Â·  Source: nvm-sh/nvm

It would be nice if we had a ".nvmrc" file for a project, kind of like ".rvmrc" for ruby. I'll start prototyping this later. What do you guys think?

feature requests

Most helpful comment

I would pay 2$ if somebody implements this feature.

All 105 comments

I'm not sure what it would do. NVM doesn't wrap the node executable, it just helps you manage multiple $PATH values.

Switch to the node version specified in .nvmrc? Why not use the package.json file?

But what will do the switching? Are you going to run nvm readconfig or something every time you enter a new folder?

As far as I know the rvm checks on every cd if the new folder contains a rvmrc and loads the appropriate config/ruby version. Maybe a ruby expert should say something about this :)

http://beginrescueend.com/workflow/rvmrc/

I just looked at how rvm implemented this. I am going to do the same approach.

I like this idea too, except that using the package.json instead of a separate .npmrc makes a a lot of sense to me as @booo says

There is already an engine version specified in the package.json file. There is zero need to add yet another dotfile to do this.

I'd love for nvm to do this automatically as well. But definitely _not_ by adding yet another .whateverc.

Hi guys,

For those interested, I spent some time this week end to write a proof of concept around the idea of parsing the package.json on a cd. Actually I use a ruby script to parse the json file and define what to do, since my bash-jutsu is quite limited. I didn't work much on the version operators either, so there's only a limited support (>=, <= and = are supported actually).

The fork can be found here:
https://github.com/abe33/nvm/tree/feature_automatic_use_on_cd_with_package

Idea: regarding "auto-switching", would it be better if we just add an nvm command to pick the best version that's suited to the current folder's package.json?

something like

nvm select # auto-select a local version that best matches what's specified in package.json

I have used rvm before and honestly didn't like the cd-stealing approach. I already have a few commands that try to steal my cd (autojump and rvm for example) and does some extra processings that I'm not aware of. IMO, running anything automatically on a cd is a bad approach.

@chakrit : The last version includes the nvm select command as you requested and dissociate the change directory hook in a separate file. I also added the support for all the version range expressions (as documented here: https://npmjs.org/doc/json.html#dependencies, minus the git and http ones). I guess there's some edge cases I didn't tested yet, I'll update it as soon as I'll find them.

@abe33 nice! :) using your fork right now.

EDIT: ruby? ಠ__ಠ

@chakrit : Yes, as I said in my first comment, my skills with shell script aren't that good, and I had hard times to find out how to parse a json file with pure shell - re-writing a json parser wasn't really part of the plan ^^ - and writing the version matching algorithm was beyond my knowledge by far.
If people have advice to how implement this in shell, I'll gladly try to port the ruby code :).

Related feature requst: http://cnodejs.org/topic/516a1f0e6d382773062dfd8a
I think use packge.json for auto-switching is a nice solution.

I also think it would be nice to add an nvm command that can try to figure out the engine to use by parsing the package.json. I have a lot of projects with different node versions, so it’d be a time saver if I don’t have to go look into package.json myself to figure out which version I want to tell nvm to use.

But yeah, I’m not sure how easy it is to parse package.json in pure Bash.

@hydrozen sounds like you need a new tool. Let's not bloat nvm with complex features like this. Searching recursively through package.json files is non-trivial for a bash function. (parsing a single json file in bash is hard enough) Write a new tool that works in any version of node that outputs a string for the ideal node version to run, and then pass that string to nvm.

I'm going to close this issue. After thinking about this for a while, it's outside the scope of nvm. Nvm is used to install and switch between versions of node manually. There is an automatic default version, but I really want to keep the tool simple.

I do think it would be a great project for someone to create a new tool written in node.js that looks at the package.json files in the current working tree and outputs the ideal node version to run. This tool will need to be installed somewhere outside nvm's tree and in your $PATH so that it will stay in scope as you switch between node versions. It can use #!/bin/env node in it's shebang. JSON parsing and file reading API's haven't changed in node in a long time, so it should run in nearly any version you want to use.

@creationix No pb for me, the ruby code can easily be ported to js so I'll give it a try when I can find some spare time.

It will be a cool thing to have!

I would pay 2$ if somebody implements this feature.

@potomak you'll pay someone to write a patch I've said I won't accept, or pay someone to write a separate utility as I suggested? (If it's the first, you'll just have to maintain a fork to keep the patch. there won't be hurt feelings)

@creationix the best would be to get this patch merged inside your repo (note I'd give part of that _bounty_ to you as the maintainer of the project) but I could pay also for the second solution.

@creationix plugin nag : )

The .nvmrc is already read when calling nvm use, so what is the point of this issue? Or is it me being ignorant right now?

@koenpunt right, I was talking about parsing package.json in nvm. That's outside the scope of the project.

I didn’t even know about the .nvmrc file. That’s good enough for me.

@creationix Have you considered something like this?

nvm use $(node -e 'console.log(require("./package.json").engines.node)')

That doesn't work if the engine is defined as >=0.4.0..

@koenpunt , depending on the semantics you desire, you can use something like this if you want to use the least-recent supported version in package.json

nvm use $(node -e 'console.log(require("./package.json").engines.node.replace(/[^\d\.]+/g, ""))')

That's not the only exception, see https://npmjs.org/doc/json.html and https://github.com/isaacs/node-semver

Version range descriptors may be any of the following styles, where "version" is a semver compatible version identifier.

  • version Must match version exactly
  • =version Same as just version
  • >version Must be greater than version
  • >=version etc
  • <version
  • <=version
  • ~version See 'Tilde Version Ranges' below
  • 1.2.x See 'X Version Ranges' below
  • http://... See 'URLs as Dependencies' below
  • * Matches any version
  • "" (just an empty string) Same as *
  • version1 - version2 Same as >=version1 <=version2.
  • range1 || range2 Passes if either range1 or range2 are satisfied.
  • git... See 'Git URLs as Dependencies' below

@koenpunt useful tip. It would be nice if this is automatically called after navigating to the folder that containing .nvmrc

@activars you'd have to patch "cd" for that, which is far outside of the scope of nvm :-)

I've written the following shell script, which depends on the semver module to pick _exactly_ the perfect node version (latest version possible, as allowed by the engines field):

function getFromPackage () {
    $(which node) -e "console.log(require('./package.json').${1})";

    if [ "$?" != "0" ]; then
        echo "Not found in package.json: $1";
        exit 1;
    fi
}

node () {
    nvmPath="/nvm";
    semverPath="$nvmPath/v0.8.25/bin/semver";

    range=getFromPackage('engines.node');

    nodeVersions=$(find "$nvmPath" -maxdepth 1 -type d -name 'v*' -printf '%f\n');
    if [ "${nodeVersions}" = "" ]; then
        echo "No installed Node.js versions could be found in $nvmPath";
        return 1;
    fi;

    nodeVer=$($semverPath --range "$range" $nodeVersions | tail -1);
    if [ "${nodeVer}" = "" ]; then
        echo "No installed Node.js versions match range '${range}'";
        return 1;
    fi;

    (nvm use $nodeVer > /dev/null 2>&1 && $(which node) $*);

    ret=$?;

    tset;
    return $ret;
}

I'm sure it's not perfect, but could be the basis for something better? Feedback encouraged :)

This is very important. As let say I only want to run with versoin 0.11.2 not higher. E.g if I run with a higher version of node my database data could get corrupted. An 'nvmrc' implementation would prevent this.

@denysonique If that's the case you should probably do some version checking in your app..?

@denysonique Odd versions of node are unstable. You shouldn't be using them with production data, ever.

For anyone interested in building a robust tool similar to what RVM is doing, most of the code for how RVM handles this seems to be in here and here.

Quick Fix:
IF YOU USE rvm already... or you just just have it installed:

  1. Create an .rvmrc file touch .rvmrc
  2. subl .rvmrc
  3. type nvm use 0.11
  4. save
  5. Go up cd .. and go in the your folder.

RVM will execute it anyways.

@intuivo in this case, I prefer to use autoenv https://github.com/kennethreitz/autoenv

@creationix I think that feature would be very welcome to NVM and I still think that it wouldn't make NVM more complex at all.

It's also useful for each CI environment as well. so that each project in the CI are isolated automatically by nvm.

@activars #truestory :+1:

@activars to quote myself:

The .nvmrc is already read when calling nvm use, so what is the point of this issue? Or is it me being ignorant right now?

So in a CI environment you would only have to run nvm use to have the correct node environment.

@activars the point of using the .nvmrc like .rvmrc is that you don't need to run any other command to make it work. When go inside of your project's folder RVM automatically loads the correct ruby version based on the .rvmrc file... no need to run nvm use.

nvm use is nice but it could be nicer if it could work like rvm/rbenv/pyenv already does.

This is because rvm patches cd, which I don't like. And rbenv creates so called "shims" which load the environment. Which could be an option, create ~/.nvm/bin/node which detects if there is a .nvmrc file in the current directory.

But this would mean these "shims" have to be created for every binary like coffee, grunt, lesscss

I quite like the shin approach.

Sent from my iPhone

On 15 Apr 2014, at 18:28, Koen Punt [email protected] wrote:

This is because rvm patches cd, which I don't like. And rbenv creates so called "shims" which load the environment. Which could be an option, create ~/.nvm/bin/node which detects if there is a .nvmrc file in the current directory.

But this would mean these "shims" have to be created for every binary.

—
Reply to this email directly or view it on GitHub.

rbenv-style shims and patching cd are far outside the scope of this project, and won't happen.

Let's all please stop providing additional plus ones - If anyone wants to open a PR, or file an issue, for a very tightly focused and small way that nvm can utitilize .nvmrc, I'm happy to consider it - see #318 - but this issue will remain closed.

I think what some of the commenters here are missing is that this project team isn't saying the solution shouldn't exist. They're saying that it shouldn't be part of this project.

There's nothing prohibiting someone from creating a tool, auto-nvm-env, that reads .nvmrc (or .node_version to mirror rvm's support for .ruby_version). In fact, it sounds like that's what they'd encourage.

@wbyoung I can't see why it shouldn't be part of NVM but ok... you already made a decision 2 years ago ;-)

@igorescobar well because the project team said no (and as you pointed out, long ago). That decision is likely due to the fact that it's a lot more code to maintain, code that really doesn't have much to do with the project as it stands. That's what we've heard from them, and we have to respect that.

It's really not that big of a deal for them to say no. It doesn't change anything. It's just one more tool to install if/when someone creates that tool. They don't want to create it or maintain it which is completely understandable.

@wbyoung OMHO I still think that they are refusing to accept it just because they comparing effort versus delivery. There are a lot more cons than pros... not just because it's out of scope but it's because not worth the effort... which is fair enough.

From engineering point of view, it makes sense to separate concerns.

It's a choice of which we decide to serve, tech or human.

I think people love this project because it makes our life easier to manage node versions for many Node projects. If we are not developing node apps, this project won't even be used. This issue isn't diverging away from the goal of serving developers by making things manageable and automated.

Of course we don't want hacks. maybe we can take look the shim approach by implementing plugins API to nvm?

Just my opinion..

Sent from my iPhone

On 15 Apr 2014, at 22:24, Igor Escobar [email protected] wrote:

@wbyoung OMHO I still think that they are refusing to accept it just because they comparing effort versus delivery. There are a lot more cons than pros... not just because it's out of scope but it's because not worth the effort... which is fair enough.

—
Reply to this email directly or view it on GitHub.

@activars agreed.

Hi all, I started a project to try to tackle this issue. Pull requests welcome!

@wbyoung :+1: Like the project

@ljharb @ronkorving instead of overriding cd or node, I've just utilised an existing behaviour in bash that allows you to modify the prompt: https://github.com/airtonix/bash-dot-files

My 2 cents since I don't need to switch often

alias nvmrc="nvm install \$(cat .nvmrc)"
alias nvmdefault="nvm use 5"

@MoOx that's unnecessary. nvm install will always read from .nvmrc if it's present.

Haha. Ok :feelstupid:
Thanks for the notice!

Not sure where this issue stands but I got this working easily with an addition to my .bash_profile.

enter_directory(){
    if ["$PWD != "$PREV_PWD"]; then
        PREV_PWD="$PWD";
        if [-e ".nvmrc"]; then
            nvm use;
        fi
    fi
}
export PROMPT_COMMAND=enter_directory

gist - https://gist.github.com/jusopi/fa6d03321991620778a2

@jusopi that's very nice, I like doing it in PROMPT_COMMAND rather than overwriting cd.

To keep from overwriting any existing PROMPT_COMMAND, I edited the last line to:

export PROMPT_COMMAND="$PROMPT_COMMAND enter_directory ;"

ZSH hook for this: https://gist.github.com/ohcibi/986fe0876b1cf746d1e8

autoload -U add-zsh-hook
load-nvmrc() {
  if [[ -f .nvmrc && -r .nvmrc ]]; then
    nvm use
  fi
}
add-zsh-hook chpwd load-nvmrc

@ohcibi TY very helpful -- added these lines to my .zshrc today!

@ohcibi it runs even if I'm already using the version mentioned by .nvmrc, probably something nvm should handle better

@TrevorSayre yep. That of course would be in the scope of nvm (imho). I'd say as nvm is a shell script it should even provide this function, i.e. only load-nvmrc from my snippet not the integration into zsh or whatever shell.

Is this worth another issue @creationix ?

@ohcibi Loading nvm in this way deprives you of the auto-use feature.

I'll certainly welcome an improvement that makes nvm use more efficient when you're already using that version - but since $PATH can be edited, rerunning nvm use as it does now helps ensure everything is set up correctly.

@ljharb in what way does it deprive me?

@ohcibi nvm use node && nvm alias default node && npm install -g foo and now on a new shell, you have foo, npm, and node available first thing. With your hook, do you have the same?

@ljharb of course. Why shouldn't I?

Perhaps I don't understand zsh hooks then. If it works on a standard zsh install as well as on omz, and it's an improvement over the current sourcing lines, I'd be happy to review a PR to install.sh!

I'm not an expert either. Maybe you can explain what you've expected to happen and I can tell or ask anybody if thats actually right.

@ohcibi nvm use needs to be run before you see a terminal prompt, so the PATH can be set up properly - otherwise the default node version, its npm, and its global modules, all will not be accessible.

Well.. all I can say is, when I open my shell I have my default node and when I enter that directory with the .nvmrc in it, nvm use is ran automatically and the node gets selected 8-). So for me it works.

aha, ok - so your zsh hook isn't for the first time the shell loads, it's for when you later cd into a dir with .nvmrc.

I would definitely appreciate that example being added under a special section for "Options to hook into cd and .nvmrc" or something.

@ljharb yes definitely. Note the name of the hook chpwd. Its a hook that is run when the directory is changed as you said. Where should I put that example. Simply into the readme?

Yeah, let's create a new section under "usage" called "Deeper shell integrations" or something, and add some text saying that these options are unsupported and optional - and then each thing will be a line item describing what shells it supports, what it does, and how you'd use it.

@ohcibi @ljharb avn works via the chpwd hook, but also works with bash. Perhaps pointing to it in the README would cause fewer questions/issues popping up here & more issues popping up in a place that's dedicated to the shell integrations.

@wbyoung want to PR a link to it in the readme under that section?

Hello,
I just tried @ohcibi 's solution and added the following to my .zshrc

# Auto change the nvm version based on a .nvmrc file based on the current directory. See https://github.com/creationix/nvm/issues/110#issuecomment-190125863
autoload -U add-zsh-hook
load-nvmrc() {
  if [[ -f .nvmrc && -r .nvmrc ]]; then
    nvm use
  fi
}
add-zsh-hook chpwd load-nvmrc

I've created a .nvmrc file in two projects, one using 0.12.12 and the other using 5.5.0.

When I open both projects using WebStorm IDE and run a nvm current in the internal console (using zsh) I see the proper version displayed. (meaning it works great, or at least that's what it looks like).

But when I manually cd into one project to another using a proper zsh shell (not from the IDE) it displays the same version. Did I miss something? I thought using cd would automatically run nvm use if a nvmrc file exists.

And I'm wondering what happens if I have two shells open at the same time in different project, showing a different version. Is nvm able to use one version by directory and somehow manage to use several different versions at the same time? Or is my shell lying and actually using the latest nvm version loaded? Thanks for input.

@Vadorequest the hook should in fact be executed whenever you cd into a directory. There might be something wrong with your environment but this is out of scope (as stated in the readme) please post that question on stackoverflow or similar.

@ljharb close this issue?

@ohcibi Okay, I just wanted to know if I missed a step or not.

What about that part?

And I'm wondering what happens if I have two shells open at the same time in different project, showing a different version. Is nvm able to use one version by directory and somehow manage to use several different versions at the same time? Or is my shell lying and actually using the latest nvm version loaded?

Thanks.

@Vadorequest each shell session has its own environment, but thats _way_ out of scope of this project 8-).

Oh, I wasn't aware of that. Thank you ;)
PS: It works fine, I just forgot to save the zshrc, sublime text... ;)

I think this is a must-be feature for nvm.

Don't you ever work with multiple projects at the same time period, guys? Do you really love to check 'uhmm.. which node version I had used for this particular project..'? This process should be automated and .rvmrc is a very good example.

It's not a fact of simplicity not having this feature. If you would really like that kind of 'simplicity' you wouldn't use a tool like nvm and you would just keep changing the paths manually.

I vote +1 for reconsideration.

@scaryguy we have had .nvmrc for a very long time (since April 2014), so no reconsideration is needed. The only remaining thing being discussed on this thread is automatically hooking into cd to run nvm use for you.

My solution isn't a solution generic enough but I mixed together the previous suggestions with stackoverflow to add the following for mac in my ~/.bash_profile and it worked well:

# change title name of tab in terminal
function title {
    echo -ne "\033]0;"$*"\007"
}

cd() {
  builtin cd "$@" || return
  #echo $PREV_PWD
  if [ "$PWD" != "$PREV_PWD" ]; then
    PREV_PWD="$PWD";
    title $(echo ${PWD##*/}) $(node -v);
    if [ -e ".nvmrc" ]; then
      nvm use;
      # set tab terminal name to be cwd and node version
      title $(echo ${PWD##*/}) $(node -v);
    else
      nvm use default;
    fi
  fi
}

Now I can do:

$ cd ~/dev/
Now using node v0.10.44
$ cd ~/dev/ts-sandbox-2/
Found '~/dev/ts-sandbox-2/.nvmrc' with version <4>
Now using node v4.4.7
$ cd ~/dev/
Now using node v0.10.44

Fun right?

Great to see work on this. Any chance in the absence of .nvmrc, it could use the engine setting in package.json. I would prefer to set the version once for the whole repo.

Also, I made https://www.npmjs.com/package/strict-version to help with forcing version

@kirkstrobeck that would require parsing JSON in POSIX, as well as handling semver ranges. It's not feasible at this time.

Sure, but I’ve got to believe that work is already done and just needs to be added as a lib, how does npm handle it?

npm does it in JS, since they have node available. nvm has to operate without node. nvm also is a single sourced shell file - it can't have any "libs" that aren't built into all POSIX systems.

Inspired by @jusopi, I wanted to automate setting up the correct node version. I chose to parse package.json using the command line utility jq. Also removed the directory check, since if I'm cding to the same directory, chances are I want to run these commands again regardless:

function enter_directory {
    if [[ -e "package.json" ]]; then
        nvm use `cat package.json | jq -r '.engines.node'`;
    fi
}

export PROMPT_COMMAND=enter_directory

Not super robust, but keeps from having to duplicate node version in different places. We pin down an exact version in our projects anyway.

nm, I need that directory check, as it runs every time a prompt is shown:

function enter_directory {
    if [[ $PWD == $PREV_PWD ]]; then
        return
    fi
    PREV_PWD=$PWD
    if [[ -e "package.json" ]]; then
        nvm use `cat package.json | jq -r '.engines.node'`;
    fi
}

Well, I use the old version of the script and it worked fine e when using cd, but when opening a prompt from an ide such as Vscode, it didn't used the cd command when opening a prompt, leading myself into issues such as installing a package in the wrong version and messing everything up.

Would be nice if nvm would understand semver, e.g.:

nvm install ">6"
nvm use ">6"
# etc.

@olalonde Writing a semver parser in posix is not a trivial task. However, nvm install 6 will do what you want, as will nvm install 6.1, or nvm install --lts (lts/* in .nvmrc), or nvm install --lts=boron (lts/boron in .nvmrc), or nvm install node (which is the latest version).

fish shell:

functions cd
function cd --description 'Change directory'
    set -l MAX_DIR_HIST 25

    if test (count $argv) -gt 1
        printf "%s\n" (_ "Too many args for cd command")
        return 1
    end

    # Skip history in subshells.
    if status --is-command-substitution
        builtin cd $argv
        return $status
    end

    # Avoid set completions.
    set -l previous $PWD

    if test "$argv" = "-"
        if test "$__fish_cd_direction" = "next"
            nextd
        else
            prevd
        end
        return $status
    end

    builtin cd $argv
    set -l cd_status $status

    if test $cd_status -eq 0 -a "$PWD" != "$previous"
        set -q dirprev[$MAX_DIR_HIST]
        and set -e dirprev[1]
        set -g dirprev $dirprev $previous
        set -e dirnext
        set -g __fish_cd_direction prev
    end

    if test -f .nvmrc
      nvm use
    end

    return $cd_status
end

@greyhawk nvm doesn't support fish, so i'm not sure how that's working.

I'll add my variation of the a Bash alias you can use to perform this automatic switching.

cdnvm(){
  cd $1
  if [[ -f .nvmrc && -s .nvmrc && -r .nvmrc ]]; then
    <.nvmrc nvm install;
  elif [[ $(nvm current) != $(nvm version default) ]]; then
    nvm use default;
  fi
}
alias cd='cdnvm'

As a one-liner:

alias cd='cdnvm(){ cd $1; if [[ -f .nvmrc && -s .nvmrc && -r .nvmrc ]]; then <.nvmrc nvm install; elif [[ $(nvm current) != $(nvm version default) ]]; then nvm use default; fi; };cdnvm'

To run on your shell:

echo 'alias cd='\''cdnvm(){ cd $1; if [[ -f .nvmrc && -s .nvmrc && -r .nvmrc ]]; then <.nvmrc nvm install; elif [[ $(nvm current) != $(nvm version default) ]]; then nvm use default; fi; };cdnvm'\''' >> ~/.bashrc

asciicast

If you're using fish, but don't want to modify the cd function.

function __use_nvmrc --on-variable PWD --description 'Use .nvmrc if it exists'
  # https://github.com/fish-shell/fish-shell/issues/583#issuecomment-13758325
  status --is-command-substitution; and return

  # https://github.com/creationix/nvm/issues/110#issuecomment-324228987
  if test -f .nvmrc
    nvm use
  end
end

@ljharb greyhawk might be using this oh-my-fish plugin for nvm. Easy way to get nvm working in fish shells.

I've updated my last alias. It's longer but is smarter about how it finds the .nvmrc file.

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)

        # Add the `v` suffix if it does not exists in the .nvmrc file
        if [[ $nvm_version != v* ]]; then
            nvm_version="v""$nvm_version"
        fi

        # If it is not already installed, install it
        if [[ $(nvm ls "$nvm_version" | tr -d '[:space:]') == "N/A" ]]; then
            nvm install "$nvm_version";
        fi

        if [[ $(nvm current) != "$nvm_version" ]]; then
            nvm use "$nvm_version";
        fi
    fi
}
alias cd='cdnvm'

Also see https://asciinema.org/a/191898

To elaborate on @greyhawk great fish alias, here is another version that:

  • find recursively .nvmrc in parent directories
  • load nvm version only if necessary
  • restore default version if no .nvmrc found

$HOME/.config/fish/functions/find-up.fish

function find-up --description 'Find file recursively in parent directory'
    set path (pwd)
    while test "$path" != "/" ; and not test -f "$path/$argv[1]"
        set path (dirname $path)
    end
    if test -f "$path/$argv[1]"
        echo "$path/$argv[1]"
    else
        echo ""
    end
end

$HOME/.config/fish/functions/cd.fish

function cd --description 'alias cd cd'

    set -l MAX_DIR_HIST 25

    if test (count $argv) -gt 1
        printf "%s\n" (_ "Too many args for cd command")
        return 1
    end

    # Skip history in subshells.
    if status --is-command-substitution
        builtin cd $argv
        return $status
    end

    # Avoid set completions.
    set -l previous $PWD

    if test "$argv" = "-"
        if test "$__fish_cd_direction" = "next"
            nextd
        else
            prevd
        end
        return $status
    end

    builtin cd $argv
    set -l cd_status $status

    if test $cd_status -eq 0 -a "$PWD" != "$previous"
        set -q dirprev[$MAX_DIR_HIST]
        and set -e dirprev[1]
        set -g dirprev $dirprev $previous
        set -e dirnext
        set -g __fish_cd_direction prev
    end

    set loaded_version (node --version)
    set nvmrc (find-up '.nvmrc')
    if test -f $nvmrc
        set nvmrc_version (cat $nvmrc)
        if test $loaded_version != $nvmrc_version
            nvm use --silent
        end
    else
        if string match -q -- "*/.nvm/*" $PATH
            nvm unload
        end
    end

    return $cd_status
end

EDIT

After playing with @Jamesford's solution, I think it's even more powerful!

Very interesting thread 🎉

Was this page helpful?
0 / 5 - 0 ratings