Nvm: NVM getting very slow on startup in Bash

Created on 29 Oct 2016  ·  191Comments  ·  Source: nvm-sh/nvm

I love NVM, but I've noticed that NVM is getting really slow during startup. See attached screenshot for what I mean: http://take.ms/LPOv3

Is this a bug or is something wrong on my Mac?

needs followup performance

Most helpful comment

So in zsh this should be

# Defer initialization of nvm until nvm, node or a node-dependent command is
# run. Ensure this block is only run once if .bashrc gets sourced multiple times
# by checking whether __init_nvm is a function.
if [ -s "$HOME/.nvm/nvm.sh" ] && [ ! "$(whence -w __init_nvm)" = function ]; then
  export NVM_DIR="$HOME/.nvm"
  [ -s "$NVM_DIR/bash_completion" ] && . "$NVM_DIR/bash_completion"
  declare -a __node_commands=('nvm' 'node' 'npm' 'yarn' 'gulp' 'grunt' 'webpack')
  function __init_nvm() {
    for i in "${__node_commands[@]}"; do unalias $i; done
    . "$NVM_DIR"/nvm.sh
    unset __node_commands
    unset -f __init_nvm
  }
  for i in "${__node_commands[@]}"; do alias $i='__init_nvm && '$i; done
fi

Since whence -w is ~ the same as type -t in bash?

All 191 comments

What's nvm ls and nvm debug print out?

You can also try adding --no-use to the end of the second nvm line (the one doing the sourcing) to confirm that it's the auto-use code path that's being slow.

@ljharb
Adding --no-use makes it superfast, but then it doesnt load node. But I guess it confirms that the auto-use code path is slow. Here are the nvm ls and nvm debug

nvm ls
->       v6.9.1
default -> 6.9.1 (-> v6.9.1)
node -> stable (-> v6.9.1) (default)
stable -> 6.9 (-> v6.9.1) (default)
iojs -> N/A (default)
lts/* -> lts/boron (-> v6.9.1)
lts/argon -> v4.6.1 (-> N/A)
lts/boron -> v6.9.1
nvm debug
nvm --version: v0.32.1
$SHELL: /bin/bash
$HOME: /Users/Andreas
$NVM_DIR: '$HOME/.nvm'
$PREFIX: ''
$NPM_CONFIG_PREFIX: ''
nvm current: v6.9.1
which node: $NVM_DIR/versions/node/v6.9.1/bin/node
which iojs:
which npm: $NVM_DIR/versions/node/v6.9.1/bin/npm
npm config get prefix: $NVM_DIR/versions/node/v6.9.1
npm root -g: $NVM_DIR/versions/node/v6.9.1/lib/node_modules

Do you have a .nvmrc file anywhere, like ~/.nvmrc?

@ljharb the one line I have in that file is
onload-script=npm-autoinit/autoinit

Tried to remove it, didn't make any difference, so added it back.

@ahennie in a file called nVmrc, you have that line?

Can you provide a little more info on your Mac? Do you have an SSD, how old is it, how fast/much RAM, etc?

This is also very slow for me on gentoo linux.

@mitermayer can you also go through the same steps above and see if you get the same or different results?

@ljharb Sorry, that was .nPmrc. I don't have a .nVmrc-file. It must be sw, not hw related. I got Macbook Pro 15" i7, 16gb RAM, SSD. What could it be?

@ahennie that should be fast enough. Basically it's that nvm use calls into npm config get prefix, which is very slow. I'll keep looking into it.

@ljharb thanks. it wasnt slow like this earlier. does the number of global modules affect the speed? other things I can do to speed it up?

When you say "earlier" do you mean on an earlier version, before I was doing prefix checking? Or do you mean on the same version of nvm?

same issue too.

@ljharb it's hard to say. I installed nvm months ago, but never really used node. However loading the bash has always been fast. I have been coding node a lot more lately, including installing a few global modules, and it suddenly have gotten slower. I also updated to the newest version of nvm, npm and node. Deleted a few global modules now, but it's still slow. So I think the slowness was intruduced in any of the updates.

It's likely the npm config get prefix call then.

@ljharb suddenly it's faster again. don't know why. but I thought you should know, before you spend to much time on it.

I just checked out the latest tag and noticed this. I forget what tag I was previously using but it was in the v0.31 series.

Adding the the --no-use fixes the issue.

Experiencing the same problem. Everything was fine until I upgraded OSX to Sierra a few days ago. Ran brew update and brew upgrade, but it's still slow. --no-use Makes it better, but still slightly slower than what it was before I upgraded.

When I run nvm ls It takes about 2-3 seconds to start, then lists everything down to system then takes 2-3 seconds for every alias after that. Here is my output:

➜  ~ nvm ls
        v5.10.1
         v6.1.0
         v6.6.0
->       v6.9.1
         system
default -> v6.9.1
node -> stable (-> v6.9.1)
stable -> 6.9 (-> v6.9.1) (default)
iojs -> iojs- (-> system) (default)
lts/* -> lts/boron (-> v6.9.1)
lts/argon -> v4.6.2 (-> N/A)
lts/boron -> v6.9.1

I'm running a 2013 15in macbook pro. 2.7Ghz, 16GB RAM.
I'm using iterm2 and oh-my-zsh, but saw someone else here had the same problem with bash.

@Nick011 nvm is not supported via homebrew (the homebrew formula says this when you install it). If you brew uninstall nvm, and then install it properly via the curl script in the readme, my suspicion is that it will go much faster.

same issue here... --no-use fixes it but also fails to load node

@nico1510 right, the npm config get prefix call that nvm is making when running nvm use is the slowest part. I don't yet have a solution to speed that up.

To investigate the performance issues myself, I tried to setup some performance logging in a forked branch:
https://github.com/martinheidegger/nvm/tree/debug/performance

and I also come to the conclusion that the biggest issue is starting node. _(npm config get prefix is a node script, as opposed to all the other scripts)_.

@martinheidegger i think you're spot on. If anyone can come up with a way to perfectly emulate npm config get prefix without invoking node (especially if it can be PRred into npm itself so that they'll keep it up to date), that would likely erase most people's performance issues.

@ljharb I ran another test for the performance of npm config get prefix and it seems to have not changed much over the versions: https://gist.github.com/martinheidegger/32d00e90e0163a22a4ffc78df796001e

I opened https://github.com/npm/npm/issues/15149~~ added comments to https://github.com/npm/npm/issues/14458#issuecomment-265054431 in order to let the npm team know of this problem as well (with some extended info).

I opened https://github.com/nodejs/help/issues/396 in order to figure out if Node.js and NPM could share the same logic in order for nvm to not need to rely on Node and/or make NPM faster.

Quoting:

If npm wanted to use that, they should file an issue or pull request to make it public API.

I guess same can be said of nvm?

It hangs on my macOS Sierra on npm get config prefix and never finishes (I waited a few minutes, then gave up). This happens both on a fresh install of nvm with either Node 6 or 7 as the only installation.

If i reinstall nvm and install only Node 4, it executes super quickly

@vvondra what does nvm debug print out, and what's echo $NVM_DIR; whoami; echo $HOME print out?

Installed by install me script from README.md

nvm debug

nvm --version: v0.33.2
$SHELL: /usr/local/bin/zsh
$HOME: /Users/nem
$NVM_DIR: '$HOME/.nvm'
$PREFIX: ''
$NPM_CONFIG_PREFIX: ''
$NVM_NODEJS_ORG_MIRROR: ''
$NVM_IOJS_ORG_MIRROR: ''
shell version: 'zsh 5.3.1 (x86_64-apple-darwin16.3.0)'
uname -a: 'Darwin 16.6.0 Darwin Kernel Version 16.6.0: Fri Apr 14 16:21:16 PDT 2017; root:xnu-3789.60.24~6/RELEASE_X86_64 x86_64'
OS version: Mac 10.12.5 16F73
curl: /usr/bin/curl, curl 7.51.0 (x86_64-apple-darwin16.0) libcurl/7.51.0 SecureTransport zlib/1.2.8
wget: /usr/local/bin/wget, GNU Wget 1.19.1 built on darwin16.4.0.
git: /usr/local/bin/git, git version 2.13.0
nvm current: v6.10.3
which node: $NVM_DIR/versions/node/v6.10.3/bin/node
which iojs: iojs not found
which npm: $NVM_DIR/versions/node/v6.10.3/bin/npm
npm config get prefix: $NVM_DIR/versions/node/v6.10.3
npm root -g: $NVM_DIR/versions/node/v6.10.3/lib/node_modules

Perf without npm use

❯ for i in $(seq 1 3); do /usr/bin/time zsh -i -c exit; done
        0.28 real         0.14 user         0.14 sys
        0.28 real         0.15 user         0.14 sys
        0.29 real         0.15 user         0.14 sys

performance when nvm use is called via

❯ for i in $(seq 1 3); do /usr/bin/time zsh -i -c exit; done
Found '/Users/nem/.nvmrc' with version <6>
Now using node v6.10.3 (npm v5.0.0)
        2.88 real         1.84 user         1.02 sys
Found '/Users/nem/.nvmrc' with version <6>
Now using node v6.10.3 (npm v5.0.0)
        2.90 real         1.86 user         1.03 sys
Found '/Users/nem/.nvmrc' with version <6>
Now using node v6.10.3 (npm v5.0.0)
        3.02 real         1.95 user         1.06 sys
❯ echo $NVM_DIR; whoami; echo $HOME
/Users/nem/.nvm
nem
/Users/nem

Also this line being added to .zshrc or .bashrc adds a 1s if not more of overhead.

https://github.com/creationix/nvm/blob/master/install.sh#L317

Which is also removed from my .zshrc.

Notice I am lazy loading the heck out of all version managers as they are all too slow.

I am also having this problem.

Same. Standard bash.

I also have a slow terminal startup because of nvm. After making some research I see that this issue pops up on github since 2014. I mean.. just LOL

Adding additional comments with +1 , "same here" , "also having...", etc.. are not productive. This is entirely the purpose of emoticons with thumbs up. Please reply with productive feedback . For example:

  • your configuration and version of nvm
  • timings with and without nvm
  • timings of different versions of nvm (helps figure out where some of the initial issues began)
  • maybe even dig into the nvm code base and give some feedback.

So start adding thumbs up to productive feedback posts and the initial post.

@Janaka-Steph that's not really productive. npm config get prefix continues to be slow, and https://github.com/npm/npm/issues/14458 tracks that.

Jul 27, still having this issue. Any way to cache the locations instead of setting them every time??

@uwnot the slowness is npm config get prefix, and there's nothing otherwise that's slow TO be cached.

i finally fixed it, now it takes just a few milliseconds

what did i do? bought a new macbook 😂 no joke, my Air 2015 was really old, turns out newer macbooks don't have this kind of issue

I get around this issue by replacing the nvm installed lines in my .bashrc with the following

export NVM_DIR="$HOME/.nvm"
export PATH=$NVM_DIR/versions/node/global/bin:$PATH
export MANPATH=$NVM_DIR/versions/node/global/share/man:$MANPATH
nvm() {
  [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"  # This loads nvm
  nvm "${@}"
}
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"  # This loads nvm bash_completion

Then, whichever node I symlink into $NVM_DIR/versions/node/global/ is readily available on the system and nvm is only slow to start the first time I invoke it. I'm debating whether to patch my installation of nvm to maintain my $NVM_DIR/versions/node/global/ link, but I don't have a need for this right now.

A bit more info: on my system the slowness is caused by node itself (npm config get prefix is slow since npm is a node script). I used valgrind's callgrind tool to identify the slowness of even a simple node script--it looks to me like the syntax parsing and code generation process is kindof slow on my old CPU.

Same problem. Solution of novakka4096 not working.

My workaround was to extract the loading of nvm to a separate scriptfile and alias that script as nvm.

my scriptfile:

unalias nvm
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"  # This loads nvm
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"  # This loads nvm bash_completion

my .bash_profile:

…
alias nvm='. ~/scriptfile'
…

Now my terminal starts very fast and if I need nvm/npm I just call nvm first to load it.

What @eauw suggested is working very well. This could be a pattern for the installer as well...

I've been rocking the same solution as @eauw for about a year now (though it is a bit annoying to remember to first run npm or node in term sessions that might use node in a script).

Here's my .bashrc clip that doesn't require a separate script file.

...
alias load_nvm='export NVM_DIR="$HOME/.nvm" && [ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"'
alias node='unalias node npm && load_nvm && node'
alias npm='unalias node npm && load_nvm && npm'
...

@novakka4096's solution can be modified to automatically load the latest version:

export NVM_LATEST_VERSION="$(ls -1 $NVM_DIR/versions/node | tail -1)"
export PATH=$NVM_DIR/versions/node/$NVM_LATEST_VERSION/bin:$PATH
export MANPATH=$NVM_DIR/versions/node/$NVM_LATEST_VERSION/share/man:$MANPATH

Hope it helps somebody.

@eauw seems like a great idea, will also use it.

In the meantime, let me debunk the myth of slow old machines. Below outputs are from brand new mid 2017 maxed specs MBP15:

Here's without nvm (zsh):

njbook% for i in $(seq 1 10); do /usr/bin/time zsh -i -c exit; done
        1.29 real         0.91 user         0.33 sys
        1.30 real         0.92 user         0.34 sys
        1.28 real         0.90 user         0.34 sys
        1.28 real         0.90 user         0.34 sys
        1.26 real         0.89 user         0.33 sys
        1.28 real         0.91 user         0.33 sys
        1.27 real         0.90 user         0.34 sys
        1.27 real         0.90 user         0.34 sys
        1.29 real         0.91 user         0.34 sys
        1.27 real         0.90 user         0.34 sys

here's after removal

njbook% for i in $(seq 1 10); do /usr/bin/time zsh -i -c exit; done
        0.28 real         0.22 user         0.04 sys
        0.26 real         0.21 user         0.04 sys
        0.28 real         0.23 user         0.03 sys
        0.26 real         0.21 user         0.03 sys
        0.28 real         0.22 user         0.04 sys
        0.28 real         0.22 user         0.03 sys
        0.28 real         0.22 user         0.03 sys
        0.28 real         0.22 user         0.03 sys
        0.27 real         0.22 user         0.03 sys
        0.27 real         0.22 user         0.03 sys

I wrote this script inside of my .zshrc to automatically symlink the node version found within .nvmrc to $NVM_DIR/versions/node/global, and to remove this symlink upon initializing nvm, building upon @novakka4096's suggestion.

nvm won't be initialized until you manually run the nvm command, but if the version of node specified in your .nvmrc exists, it (node, npm, npx) will be available immediately with virtually no overhead.

export PATH="$PATH:$NVM_DIR/versions/node/global/bin"

_NVM_INIT=0
_NVG=$NVM_DIR/versions/node/global
_nvm_init () {
    if [[ $_NVM_INIT == 1 ]]; then
        return
    fi
    if [[ -L $_NVG ]]; then
        rm $_NVG
    fi
    if [[ -e $_NVG ]]; then
        echo "unknown file exists at $_NVG. Manually remove it and try again." >&2
        return 1
    fi
    echo "Initializing nvm..." >&2
    unalias nvm &> /dev/null
    [ -s "$NVM_INSTALL_DIR/nvm.sh" ] && . "$NVM_INSTALL_DIR/init-nvm.sh"
    _NVM_INIT=1
    echo "Initialized nvm" >&2
}

_node_init () {
    if [[ ! -x $_NVG/bin/node ]]; then
        if [[ -L $_NVG ]]; then
            rm $_NVG
        fi
        if [[ -e $_NVG ]]; then
            echo "unknown file exists at $_NVG. Manually remove it and try again." >&2
            return 1
        fi

        if [[ -f $HOME/.nvmrc ]]; then
            local nv=$(cat $HOME/.nvmrc)
            local nvd=$NVM_DIR/versions/node/$nv
            if [[ ! -x $nvd/bin/node ]]; then
                echo "nvm node version $nv not found" >&2
                _nvm_init
            else
                echo "creating smylink $_NVG -> $nvd"
                ln -s $nvd $_NVG
            fi
        else
            echo ".nvmrc not found" >&2
            _nvm_init
        fi
    fi
}

_nvm () {
    _nvm_init
    nvm "${@}"
}
alias nvm=_nvm

_node_init > /dev/null

One caveat is that the version number inside your .nvmrc must be exactly the same as the directory name inside $NVM_DIR/versions/node. So, if your desired version is at $NVM_DIR/versions/node/v8.6.0, your .nvmrc must contain exactly v8.6.0. Using 8.6, 8.6.0, v8, etc won't work.

This speeds up my zsh startup time by ~7X, which is huge because I'm constantly opening new terminals.

Before:

$ for i in $(seq 1 10); do time zsh -i -c exit; done
zsh -i -c exit  0.50s user 0.20s system 109% cpu 0.641 total
zsh -i -c exit  0.53s user 0.22s system 109% cpu 0.679 total
zsh -i -c exit  0.51s user 0.24s system 110% cpu 0.679 total
zsh -i -c exit  0.51s user 0.22s system 109% cpu 0.658 total
zsh -i -c exit  0.51s user 0.22s system 110% cpu 0.665 total
zsh -i -c exit  0.52s user 0.22s system 110% cpu 0.668 total
zsh -i -c exit  0.52s user 0.22s system 110% cpu 0.668 total
zsh -i -c exit  0.54s user 0.20s system 110% cpu 0.677 total
zsh -i -c exit  0.51s user 0.23s system 109% cpu 0.673 total
zsh -i -c exit  0.52s user 0.21s system 109% cpu 0.670 total
average 0.6678

After:

$ for i in $(seq 1 10); do time zsh -i -c exit; done
zsh -i -c exit  0.07s user 0.03s system 102% cpu 0.096 total
zsh -i -c exit  0.08s user 0.01s system 102% cpu 0.087 total
zsh -i -c exit  0.06s user 0.03s system 102% cpu 0.084 total
zsh -i -c exit  0.07s user 0.01s system 102% cpu 0.085 total
zsh -i -c exit  0.07s user 0.01s system 102% cpu 0.084 total
zsh -i -c exit  0.06s user 0.03s system 103% cpu 0.085 total
zsh -i -c exit  0.07s user 0.02s system 102% cpu 0.088 total
zsh -i -c exit  0.06s user 0.03s system 103% cpu 0.088 total
zsh -i -c exit  0.07s user 0.02s system 103% cpu 0.085 total
zsh -i -c exit  0.09s user 0.00s system 102% cpu 0.084 total
average 0.0866

Hey guys! I wrote a simple app (kinda) called znvm that combines a bunch of solutions given over here for zsh users.
Features:

  • Make zsh with nvm faster by loading only if .nvmrc file found or called explicitly
  • Automatically calls nvm use if .nvmrc is present.
  • If node vesion in .nvmrv is not installed it will automatically call nvm install
  • Can be configured to load nvm before certain commands are executed on the shell (such as editors and IDEs)

check it out: https://github.com/Kasahs/.znvm
Just follow the instructions to install
I hope it helps

@ljharb can't you use which npm instead of npm config get prefix ? might not be the same thing ( and probably not work on windows ) but since it wasn't mentioned here i thought it won't hurt to remember the which command

@hems npm config get prefix isn't returning the location of the npm binary; it's returning the location that global modules will be installed into.

@ljharb i guessed "which" was too obvious and you already knew about it and i was just being unuseful ( :

my collegue uses "n" instead of "nvm" and his zsh/bash boots super quick, do you know how "n" worked around the issue?

by the way i'm using --no-use and it's now fast again, so problem solved to me!

I have been experiencing very slow loading times for months on my macbook pro 2013. Finally tracked it down to the nvm.sh script in my .bash_profile. Lazy loading the script like some other have suggested here seems like a great approach. Is someone working on making changes to the install script to make this a default?

@macadev no, lazy loading the script means you won't have access to globally installed npm binaries.

You can certainly use --no-use, and then invoke nvm use on the first node and/or npm usage, but that wouldn't be a sensible default.

That makes sense. It's a bit of a bummer that those of us with older hardware have to put up with less than optimal solutions. I'll spend sometime looking at other ways to improve this. Thanks for the quick reply.

The only true solution here is if npm config get prefix suddenly gets fast, or, if someone can provide a fast, non-insane, robust, correct method of replicating what it does across all npm versions (1 - 5).

So I have a brand new, top of the line Retina Macbook Pro 2017, and nvm takes a good ~60 seconds to startup. I'm using the https://github.com/Kasahs/.znvm so that I can at least open a new bash window without wasting a minute each time, but anything with a .nvmrc is slow. I also reinstalled nvm from scratch, deleting all relevant folders/files, and it still happens. nodenv does not have this problem at all, it makes nvm basically unusable and I've tried all the solutions above.

This is what I did: alias nvm='unalias nvm && source "$HOME"/.nvm/nvm.sh && nvm'

The solution @dwieeb gives above should be the standard until / unless the underlying Node performance issue is sorted. There's no way a MacPro should take a minute to load Terminal.

No, it should not be; see https://github.com/creationix/nvm/issues/1277#issuecomment-339207451 (and many earlier comments in this thread).

@ljharb I know full well that I don't have access to my globally installed binaries until my environment is activated. The alias trick works for me. I've seen no ill-effects using nvm this way.

You can certainly use --no-use, and then invoke nvm use on the first node and/or npm usage, but that wouldn't be a sensible default.

I'm not sure why you think it wouldn't be sensible. This is how virtualenv and similar projects have behaved for years.

@dwieeb note i'm not saying you shouldn't do this, nor that it's not sensible to do this. I'm saying it wouldn't be a sensible default for the majority of users of nvm. That other languages' projects have made choices doesn't mean they're automatically good ones. My comment is not a response to you; but rather to https://github.com/creationix/nvm/issues/1277#issuecomment-346778075 claiming "should be the standard".

I'm sorry you don't see a massive performance issue for the vast majority of your users as an issue worthy of a simple workaround in the installer until Node sort themselves out.

@tomchiverton "vast majority" is simply not the case at all; I also can't reproduce this issue on my own machine nor that of any of my colleagues. The workaround suggested is not simple, otherwise I'd employ it.

Please elaborate why deferring the actual work until 'nvm' is run the first time isn't simple.

Even more complete fix for the .bashrc issue would be something like

export NVM_DIR=...
alias nvm='unalias nvm && source "$NVM_DIR"/nvm.sh && nvm'
alias node='unalias node && nvm && node'
alias npm='unalias npm && nvm && npm'

@tomchiverton for the same reason I've mentioned many many times, that wouldn't work: https://github.com/creationix/nvm/issues/1277#issuecomment-339207451 Please read that comment a few times before posting further.

Another data point: Just doing the nvm init is taking up 75% of my zsh startup. It's ~250ms w/o and about a second with nvm.

P.S.: This is on a new MacBook Pro, latest macOS.

@jkrems are you using omz? also, does that only happen in zsh - can you repro it in bash?

I can reproduce with both the omz plugin, omz + manual init, and omz
disabled + manual init. Always 500ms+. Will try bash as well.

On Sat, Dec 16, 2017 at 9:49 AM Jordan Harband notifications@github.com
wrote:

@jkrems https://github.com/jkrems are you using omz? also, does that
only happen in zsh - can you repro it in bash?


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/creationix/nvm/issues/1277#issuecomment-352199005,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AAio9IP9zCmQEpLTcpxVWF48X9nOa5Ueks5tBAKbgaJpZM4KkDB6
.

Just tried with bash as well, it's ~500ms:

> time bash -c 'source "$HOME/.nvm/nvm.sh"'
bash -c 'source "$HOME/.nvm/nvm.sh"'  0.31s user 0.17s system 98% cpu 0.489 total

> time bash -c 'exit'
bash -c 'exit'  0.00s user 0.00s system 78% cpu 0.005 total

I'm using iterm2 and oh-my-zsh and here it is very much reading, is there any movement to improve startup performance?

I'm also getting slow initialization of terminal windows with nvm (e.g - takes about 1 second to initialize)

@gerardo-junior For what it's worth I think oh-my-zsh is pretty bad on startup performance. If you spend an afternoon hand picking plugins and configuring Zsh yourself that should help.

I believe I did a modification of this post (which was brilliant) in combination of maybe this post. Anyway now I can load nvm very fast and assign yarn to have it's globals installed under the domain of that npm version as well.

https://github.com/nmccready/zsh-settings/blob/master/.zshrc#L99-L127

This method of loading nvm relies heavily on using .nvmrc .

nvm_yarn(){
  export YARN_BIN="${NVM_DIR}/versions/node/${NODE_VERSION}/yarn"
  mkdir -p "$YARN_BIN";
  yarn config set prefix "$YARN_BIN" &> /dev/null
  export PATH="${PATH}:$YARN_BIN/bin"
}

nvm_paths(){
  if [[ -z $1 ]];then
    NODE_VERSION="v`cat $HOME/.nvmrc`"
  else
    NODE_VERSION="v$1"
  fi
  #echo node: $NODE_VERSION
  export NODE_VERSION

  export NODE_PATH="${NVM_DIR}/versions/node/${NODE_VERSION}/bin"
  export PATH="${PATH}:$NODE_PATH"
  nvm_yarn
}

nvm_use(){
 nvm_paths $1
 nvm use $1
}

export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" --no-use
nvm_paths

This also allows you to use nvm_use later.
nvm_use 8.9.3 #setup yarn too

Note: Prior to below test I commented out these lines (same problem as nvm)

❯ for i in $(seq 1 3); do /usr/bin/time zsh -i -c exit; done
        0.70 real         0.47 user         0.20 sys
        0.68 real         0.46 user         0.20 sys
        0.72 real         0.49 user         0.21 sys

❯ node -v
v6.12.2
❯ nvm --version
0.33.7

I just put together a solution to that defers initialization of nvm until it's needed that works pretty well:

# Defer initialization of nvm until nvm, node or a node-dependent command is
# run. Ensure this block is only run once if .bashrc gets sourced multiple times
# by checking whether __init_nvm is a function.
if [ -s "$HOME/.nvm/nvm.sh" ] && [ ! "$(type -t __init_nvm)" = function ]; then
  export NVM_DIR="$HOME/.nvm"
  [ -s "$NVM_DIR/bash_completion" ] && . "$NVM_DIR/bash_completion"
  declare -a __node_commands=('nvm' 'node' 'npm' 'yarn' 'gulp' 'grunt' 'webpack')
  function __init_nvm() {
    for i in "${__node_commands[@]}"; do unalias $i; done
    . "$NVM_DIR"/nvm.sh
    unset __node_commands
    unset -f __init_nvm
  }
  for i in "${__node_commands[@]}"; do alias $i='__init_nvm && '$i; done
fi

I go into more detail in this blog post: http://www.growingwiththeweb.com/2018/01/slow-nvm-init.html

So in zsh this should be

# Defer initialization of nvm until nvm, node or a node-dependent command is
# run. Ensure this block is only run once if .bashrc gets sourced multiple times
# by checking whether __init_nvm is a function.
if [ -s "$HOME/.nvm/nvm.sh" ] && [ ! "$(whence -w __init_nvm)" = function ]; then
  export NVM_DIR="$HOME/.nvm"
  [ -s "$NVM_DIR/bash_completion" ] && . "$NVM_DIR/bash_completion"
  declare -a __node_commands=('nvm' 'node' 'npm' 'yarn' 'gulp' 'grunt' 'webpack')
  function __init_nvm() {
    for i in "${__node_commands[@]}"; do unalias $i; done
    . "$NVM_DIR"/nvm.sh
    unset __node_commands
    unset -f __init_nvm
  }
  for i in "${__node_commands[@]}"; do alias $i='__init_nvm && '$i; done
fi

Since whence -w is ~ the same as type -t in bash?

type -w works in ZSH, but it adds an implicit -v flag. Doesn't seem to have any effect, but perhaps whence is still the better choice.

In my case, the results are staggering (MacBook Pro 13-inch, Early 2011, SSD):

before:

for i in $(seq 1 10); do /usr/bin/time zsh -i -c exit; done
        3.04 real         1.32 user         1.67 sys
        2.94 real         1.30 user         1.68 sys
        2.95 real         1.33 user         1.68 sys
        2.88 real         1.30 user         1.64 sys
        2.93 real         1.31 user         1.67 sys
        2.95 real         1.30 user         1.68 sys
        3.25 real         1.40 user         1.92 sys
        3.03 real         1.36 user         1.85 sys
        2.95 real         1.33 user         1.71 sys
        2.87 real         1.31 user         1.62 sys

after:

for i in $(seq 1 10); do /usr/bin/time zsh -i -c exit; done
        0.46 real         0.25 user         0.20 sys
        0.46 real         0.25 user         0.20 sys
        0.44 real         0.24 user         0.19 sys
        0.47 real         0.25 user         0.21 sys
        0.43 real         0.24 user         0.19 sys
        0.46 real         0.25 user         0.20 sys
        0.45 real         0.25 user         0.19 sys
        0.44 real         0.24 user         0.19 sys
        0.47 real         0.26 user         0.20 sys
        0.46 real         0.25 user         0.20 sys

Something like @Tyriar's solution needs to make it into nvm. It doesn't seem like npm is doing anything about npm config get prefix.

Something like @Tyriar's solution needs to make it into nvm. It doesn't seem like npm is doing anything about npm config get prefix.

I am not sure if @zkat @iarna know that this issue is a big problem for many in the nodejs community so I cc-ed them.

@Stanzilla’s solution worked perfectly for me on oh-my-zsh. Thank you!

@ljharb just guessing: can we cache result of npm config get prefix?
can we detect that cached value should be invalidated, without running npm config get prefix?
has this detection algorithm to copy npm config get prefix algorithm of every npm version?

@glukki no. it could change at any time based on filesystem or env changes, and also will change based on the directory path, because of .npmrc files.

It has been a long time since I made the PR: #1597, and also in this issue #1596 which also discussed this point. This probably will never be resolved, you can use my patch if you want a speed up, haven't had any problems with it and use it all the time.

Here are my scripts for nvm using brew installed node by default.

@JBallin fwiw it's likely that the existence of your brew-installed node is the cause of your increased nvm startup time.

@ljharb he ment shell startup time, not nvm. he completely avoids nvm here unless he needs it.

@wzrdtales yes, the implication of the comment is that they're concerned about shell startup time with nvm properly enabled - i'm suggesting that the brew-installed node, combined with enabling nvm properly, is the cause of the slowdown, and that if the brew-installed node is removed, no hacks or workarounds for nvm will be needed.

@ljharb no actually nvm is the reason for the shell slowdown, and the reason for the nvm slodown is npm. if you read his answer closely he never stated anything about nvm, but he removed nvm from his shell startup alltogether and replaced it by a dynamic script. nvm is slow this is a hard fact, that is why I have a long while ago submitted fixes to the issues, but we did not came along well and I ended up dropping the original nvm completely.

Here is a mini bench of just calling nvm from the console. Around half a second is clearly too much. And that is why people are complaining, nothing more. nvm is awesome to what it provides, it just is a bad deal for everyone that actually uses it shell to be productive, like me since i am a neovim user I operate exclusively in the shell.

time zsh nvm.sh          
zsh nvm.sh  0,39s user 0,06s system 114% cpu 0,396 total

Btw. I am still on nvms side, that is why I still watch these issues waiting for the day you finally move in and allow the fixes to be made. I wont help this time since I tried it once though, but I will be more than happy to deprecate my hard fork as soon as this gets fixed :)

@wzrdtales many people have already reported that their nvm slowdowns vanish when they uninstall their brew-installed node. I understand that it's the combination causing the issue, but uninstalling a brew-installed node so far has seemed like a viable solution.

Viable on Mac, maybe. Not so much anywhere else.

@ljharb Might be, just stated in this case, he chose a brew install instead of nvm, I don't think that the node installation was the problem but the solution over nvm. However, I don't have time for this, still hoping you will someday look into the fixes and improvements and change your mind, b/c those are easily fixable, this is just a problem of opinions here, which I am fine with I stated that already in our early conversations, still I disagree strongly. And for me it doesn't matter anyway I have my hard fork which loads in 4ms, so I've got it sorted, but I guess this discussion here will never end though.

@wzrdtales a brew install of nvm will always be broken and is totally unsupported - nvm must never be installed from homebrew.

I've already made some improvements and am working on others.

I have a fresh installation of nvm (no other installation of node) and its about 800ms of startup time on my bash.
Is the workaround above the best solution? Is the nvm team going to endorse this?

@eloytoro I'm the nvm team, and I'm not endorsing any workaround except https://github.com/creationix/nvm/issues/1277#issuecomment-257117408 (or waiting).

However, I'm actively (albeit slowly) working on addressing this problem, and will be sure to update here as I do.

Small update to @Stanzilla's script. If you're using zsh's chpwd add-zsh-hook to update the node version based on a .nvmrc or .node-version file, use this script:

load-nvmrc() {
  if [[ -f .node-version && -r .node-version ]]; then
    nvm use &> /dev/null
  elif [[ $(nvm version) != $(nvm version default)  ]]; then
    nvm use &> /dev/null
  fi
  setRightPrompt
}

# Defer initialization of nvm until nvm, node or a node-dependent command is
# run. Ensure this block is only run once if .bashrc gets sourced multiple times
# by checking whether __init_nvm is a function.
if [ -s "$HOME/.nvm/nvm.sh" ] && [ ! "$(whence -w __init_nvm)" = function ]; then
  export NVM_DIR="$HOME/.nvm"
  [ -s "$NVM_DIR/bash_completion" ] && . "$NVM_DIR/bash_completion"
  declare -a __node_commands=('nvm' 'node' 'npm' 'yarn' 'gulp' 'grunt' 'webpack' 'topgun')
  function __init_nvm() {
    for i in "${__node_commands[@]}"; do unalias $i; done
    . "$NVM_DIR"/nvm.sh
    unset __node_commands
    unset -f __init_nvm
    add-zsh-hook chpwd load-nvmrc
    load-nvmrc
  }
  for i in "${__node_commands[@]}"; do alias $i='__init_nvm && '$i; done
fi

@ljharb Since your changes are looking like you would now unlike in the past touch the npm stuff. look at #1597 and #1596 again which fixes the NPM stuff, or better does the easy standardized stuff with other toolings. And this change https://github.com/wzrdtales/nvm-ng/commit/ca95a3f3d0fc0a96c793fe287aa26870561e0f5d eliminates basically the boot time alltogether, there are some more fixes beyond that for zsh to make some of the array stuff work, that you need to pick up yourself from the commit history though. Feel free to adapt.

Additionally to that, to completely get rid of all the load time, either defer the menu initialization by default, or better just rewrite nvm in a compiled language instead.

nvm will never be written in anything but posix, and if it did, it would only ever be in JavaScript, so that’s even not worth bringing up.

Regarding #1596, that’s still open only because the specific technical choice to use npm config get prefix isn’t permanent; however, checking the prefix will never be removed.

1597 is still open because I’m still hoping you’ll adapt the PR in the way I’ve requested (which includes not removing the npm call).

@ljharb As said, I still disagree and I wont invest anymore time in that PR nor will I open one for the other improvement linked above. I tried it once, and decided for myself it is not worth the hassle and time. Since what you want is keeping npm and not allowing removing it as dependency for checking the prefix stuff, I wont adjust the PR and since it lays around for so long now and my priorities have changed I probably will never.

And you seem to get something wrong here, may be read the whole discussion in both issue and PR again. I never removed the check, I replaced it with equivalents that do the exact same as npm config get prefix and you've been the blocking factor, you even asked me to remove the removal of npm and leave the additional check added which would just make matters worse since that would mean even more loadtime due to another code path.

As said, I just brought that up once more, if you do not want to move forward with my suggestion, this is your absolute freedom, but alternatively you have to come up with something else to make your users happy. B/c for me it doesn't matter I do not use nvm anymore but my hard fork.

TL;DR; As stated above feel free to adapt, this is meant in a friendly way though. However I'm out and I wont support you.

I'd rather use a fork that fixes this rather than the original, it's quite amazing that this has been around for so long and it's still not being addressed

@eloytoro I'm lazy loading nvm using this.
Might be a good workaround for you 😸

Thanks for the script!
However I'm really interested in a more permanent fix, there is a bazillion version mangers (for python, ruby, etc) out there that do this right because its not that hard.
I'm sure we can create good software here. Otherwise I'll be creating my own node version manager

@eloytoro it's already done right - it works correctly. "Slow" is not broken, it's just a subpar experience. Not one person has yet suggested an alternative that actually works correctly with the same level of rigor and robustness, and if one appeared that was equally correct yet faster, I'd happily merge it.

If you're able to write your own per-user per-shell version manager that works correctly in this way for JS (which has different requirements than all the other languages, so those examples are irrelevant) without incurring a performance hit, I'd love to hear about it.

@ljharb Didn't wanted to state anything anymore but

Not one person has yet suggested an alternative that actually works correctly with the same level of rigor and robustness, and if one appeared that was equally correct yet faster, I'd happily merge it.

Sorry I did suggested something that actually works correctly, with the same level of rigor and robustness... .

https://github.com/wzrdtales/nvm-ng/issues/2

Replacing npm with equivalent is robust, since the stuff that was replaced is standardized in npm and will probably never change. It is sad that this went this direction, and it is sad that you feel offended @ljharb just because someone stated that he will do his own version manager. Yes that probably was kinda critique, but this is open source, if someone will do something new b/c one thing doesn't satisfy him he is free to do so. There is no reason to be offended by something like that, that just means these persons are not satisfied, no conculsion arises so they make decisions. That is how things went on, and starting a fight here doesn't make sense, since most here want or wanted to work with you together to fix it.

@wzrdtales the comments (https://github.com/creationix/nvm/pull/1597#issuecomment-325492466) I made in #1597 were intended to ask for an iterative approach, and you basically refused to accept that iterative approach - you wanted all or nothing, which is not a very safe way to validate a change, nor one that respects all the existing users.

If replacing with an equivalent is robust, then great! Convince me that's the case and we can move forward - but you've already stated you don't want to "support me" any further, so ¯\_(ツ)_/¯

I'll also note that a slow load time does not "screw up the shell" in any way - it just means you do something else for a short period of time while you wait. As-is, everything works properly, it just works slowly - and more importantly, the slowness is only experienced by a minority of users.

I'm not offended that someone stated they'd make their own version manager, I'm amused, because it's a much harder problem than people realize.

lol ok... I requote myself: I tried it once and I wont waste time anymore here, reason: in this case I don't see any sense in wasting my time with you openly spoken, due to the dialogue we already had. And yes it does screw up your shell, only beause you do not seem to use your shell it does not mean others do not. If you're using neovim + a tiling shell instead of some fancy IDE like atom or stuff, you will notice the pain as hard as it gets. But you do not seem to be a user of (neo)vim or any other powerful shell editor, so you're not affected.

And btw. that was not off topic, but lets keep it fair.

However, I promise you: I will never answer here again, I'm sorry I did, but your last sentence truly disappoints me, I thought you were better than that and still hope you are.

@ljharb I tested removing brew installed node and it still had a slow startup time. I now use the this script, which works really well for me.

@JBallin thanks for the info, that does help. As for your script, the major caveat is that globally installed modules in your default node version won't be available. What I'd recommend instead of your nvm override is to source nvm.sh with the --no-use option, which will be quite fast, and then you'd run nvm use to activate it when needed.

@ljharb --no-use works great!

I've modified the following script to profile nvm: http://www.rosipov.com/blog/profiling-slow-bashrc/ (my modifications add linenumbers: https://gist.github.com/jerroydmoore/3c59107f6c21f29be5691018b5b741b2)

Anyway the worst offender for me (it may vary depending on OS and shell) at > 0.6seconds was nvm_echo on line 840.

@jerroydmoore the nvm_echo call itself, which just calls into printf?? or the nvm_alias call inside the subshell call?

I'm using nvm with zsh and I've noticed that it is the main source of load delay after recent reinstall of the system.

Adding --no-use makes it faster, but still not as fast as removing it, but since it doesn't load node then whats the point of that anyway.

Here's time load comparison with time zsh -i -c exit:

| env | incr over prev | overall incr | output |
| ---- | ---- | ---- | ----
| clean zsh | +0 | +0 | 0.00s user 0.00s system 77% cpu 0.011 total |
| + oh-my-zsh | +0.124 | +0.124 | 0.07s user 0.06s system 94% cpu 0.135 total |
| + omz, p9k theme | +0.188 | +0.312 | 0.16s user 0.15s system 97% cpu 0.323 total |
| + omz, p9k, nvm --no-use | +0.827 | +1.139 | 0.50s user 0.37s system 75% cpu 1.151 total |
| + omz, p9k, nvm | +2.091 | +2.403 | 1.10s user 1.24s system 96% cpu 2.414 total |

That's quite a considerable increase for just nvm.

Here is the nvm related output of zsh profiler output (zmodload zsh/zprof)

num  calls                time                       self            name
-----------------------------------------------------------------------------------
 1)    1        1471.81  1471.81   64.66%    586.71   586.71   25.78%  nvm_auto
 2)    1         534.72   534.72   23.49%    534.62   534.62   23.49%  nvm_die_on_prefix
 3)    2         491.21   245.60   21.58%    221.94   110.97    9.75%  compinit
 4)    2         885.10   442.55   38.89%    202.11   101.06    8.88%  nvm
 5)   21         153.88     7.33    6.76%    151.77     7.23    6.67%  p9k::register_segment
 6)    1         142.41   142.41    6.26%    142.41   142.41    6.26%  compdump
 7)    1         142.33   142.33    6.25%    130.89   130.89    5.75%  nvm_ensure_version_installed
 8)  671         105.09     0.16    4.62%    105.09     0.16    4.62%  compdef
 9)    1         221.99   221.99    9.75%     57.65    57.65    2.53%  __p9k_load_segments
10)    5          49.20     9.84    2.16%     49.20     9.84    2.16%  compaudit
11)    1          14.64    14.64    0.64%     14.64    14.64    0.64%  __p9k_update_environment_vars
12)    1          14.14    14.14    0.62%     14.14    14.14    0.62%  nvm_supports_source_options
13)    1          11.45    11.45    0.50%     11.45    11.45    0.50%  nvm_is_version_installed
14)    1           8.47     8.47    0.37%      8.44     8.44    0.37%  __p9k_vcs_init
15)    1           8.00     8.00    0.35%      8.00     8.00    0.35%  __p9k_detect_os
16)    2           7.48     3.74    0.33%      7.48     3.74    0.33%  grep-flag-available
17)    2           6.36     3.18    0.28%      6.36     3.18    0.28%  env_default
18)    3           6.13     2.04    0.27%      6.13     2.04    0.27%  nvm_has
19)    1           7.13     7.13    0.31%      2.95     2.95    0.13%  prompt_powerlevel9k_setup
20)    1           2.92     2.92    0.13%      2.92     2.92    0.13%  __p9k_term_colors
21)    2           2.68     1.34    0.12%      2.68     1.34    0.12%  colors
22)   47           2.91     0.06    0.13%      2.58     0.05    0.11%  p9k::register_icon
23)   34           1.37     0.04    0.06%      1.21     0.04    0.05%  p9k::set_default
24)  198           1.13     0.01    0.05%      1.13     0.01    0.05%  p9k::defined
25)    1           1.12     1.12    0.05%      1.12     1.12    0.05%  is-at-least
26)    4           0.94     0.23    0.04%      0.94     0.23    0.04%  add-zsh-hook
27)    1           0.87     0.87    0.04%      0.76     0.76    0.03%  __p9k_print_deprecation_var_warning
28)    6           0.22     0.04    0.01%      0.22     0.04    0.01%  is_plugin
29)    1           0.21     0.21    0.01%      0.21     0.21    0.01%  __p9k_source_autoloads
30)    1           0.22     0.22    0.01%      0.11     0.11    0.00%  complete
31)    1        1486.03  1486.03   65.29%      0.08     0.08    0.00%  nvm_process_parameters
32)    1           0.08     0.08    0.00%      0.08     0.08    0.00%  __p9k_detect_terminal
33)    1           0.08     0.08    0.00%      0.05     0.05    0.00%  __p9k_print_deprecation_warning
34)    1           0.04     0.04    0.00%      0.04     0.04    0.00%  bashcompinit
35)    1           0.03     0.03    0.00%      0.03     0.03    0.00%  source_env
36)    1           0.02     0.02    0.00%      0.02     0.02    0.00%  p9k::segment_in_use

-----------------------------------------------------------------------------------

31)    1        1461.05  1461.05   68.37%      0.07     0.07    0.00%  nvm_process_parameters
       1/1        11.95    11.95    0.56%     11.95    11.95             nvm_supports_source_options [13]
       1/1      1449.03  1449.03   67.81%    576.77   576.77             nvm_auto [1]

-----------------------------------------------------------------------------------

       1/1      1449.03  1449.03   67.81%    576.77   576.77             nvm_process_parameters [31]
 1)    1        1449.03  1449.03   67.81%    576.77   576.77   26.99%  nvm_auto
       1/2       872.27   872.27   40.82%      7.88     7.88             nvm [3]

-----------------------------------------------------------------------------------

       1/2       872.27   872.27   40.82%      7.88     7.88             nvm_auto [1]
       1/2       864.39   864.39   40.45%    192.03   192.03             nvm [3]
 3)    2         872.27   436.13   40.82%    199.91    99.95    9.35%  nvm
       1/3         5.67     5.67    0.27%      5.67     5.67             nvm_has [18]
       1/1       148.00   148.00    6.93%    135.05   135.05             nvm_ensure_version_installed [6]
       1/1       518.69   518.69   24.27%    518.58   518.58             nvm_die_on_prefix [2]
       1/2       864.39   864.39   40.45%    192.03   192.03             nvm [3]

-----------------------------------------------------------------------------------

       1/1       518.69   518.69   24.27%    518.58   518.58             nvm [3]
 2)    1         518.69   518.69   24.27%    518.58   518.58   24.27%  nvm_die_on_prefix
       1/3         0.11     0.11    0.01%      0.11     0.11             nvm_has [18]

-----------------------------------------------------------------------------------

       1/1       148.00   148.00    6.93%    135.05   135.05             nvm [3]
 6)    1         148.00   148.00    6.93%    135.05   135.05    6.32%  nvm_ensure_version_installed
       1/1        12.95    12.95    0.61%     12.95    12.95             nvm_is_version_installed [12]

-----------------------------------------------------------------------------------

       1/1        12.95    12.95    0.61%     12.95    12.95             nvm_ensure_version_installed [6]
12)    1          12.95    12.95    0.61%     12.95    12.95    0.61%  nvm_is_version_installed

-----------------------------------------------------------------------------------

       1/1        11.95    11.95    0.56%     11.95    11.95             nvm_process_parameters [31]
13)    1          11.95    11.95    0.56%     11.95    11.95    0.56%  nvm_supports_source_options

-----------------------------------------------------------------------------------

       1/3         5.67     5.67    0.27%      5.67     5.67             nvm [3]
       1/3         0.11     0.11    0.01%      0.11     0.11             nvm_die_on_prefix [2]
18)    3           5.88     1.96    0.28%      5.88     1.96    0.28%  nvm_has

Here are nvm ls and 'debug' outputs:

$ nvm ls
         v4.0.0
         v8.0.0
       v10.12.0
->      v11.1.0
default -> stable (-> v11.1.0)
node -> stable (-> v11.1.0) (default)
stable -> 11.1 (-> v11.1.0) (default)
iojs -> N/A (default)
lts/* -> lts/dubnium (-> N/A)
lts/argon -> v4.9.1 (-> N/A)
lts/boron -> v6.14.4 (-> N/A)
lts/carbon -> v8.12.0 (-> N/A)
lts/dubnium -> v10.13.0 (-> N/A)

$ nvm debug
nvm --version: v0.33.11
$TERM_PROGRAM: iTerm.app
$SHELL: /bin/zsh
$SHLVL: 1
$HOME: /Users/n1kk
$NVM_DIR: '$HOME/.nvm'
$PATH: $NVM_DIR/versions/node/v11.1.0/bin:$HOME/bin:/usr/local/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:$HOME/dev/_sdk/haxe_4.0.0_rc5
$PREFIX: ''
$NPM_CONFIG_PREFIX: ''
$NVM_NODEJS_ORG_MIRROR: ''
$NVM_IOJS_ORG_MIRROR: ''
shell version: 'zsh 5.3 (x86_64-apple-darwin18.0)'
uname -a: 'Darwin 18.2.0 Darwin Kernel Version 18.2.0: Fri Oct 5 19:41:49 PDT 2018; root:xnu-4903.221.2~2/RELEASE_X86_64 x86_64'
OS version: Mac 10.14.1 18B75
curl: /usr/bin/curl, curl 7.54.0 (x86_64-apple-darwin18.0) libcurl/7.54.0 LibreSSL/2.6.4 zlib/1.2.11 nghttp2/1.24.1
wget: not found
git: /usr/bin/git, git version 2.17.2 (Apple Git-113)
grep: grep: aliased to grep  --color=auto --exclude-dir={.bzr,CVS,.git,.hg,.svn} (grep --color=auto --exclude-dir={.bzr,CVS,.git,.hg,.svn}), grep (BSD grep) 2.5.1-FreeBSD
awk: /usr/bin/awk, awk version 20070501
sed: illegal option -- -
usage: sed script [-Ealn] [-i extension] [file ...]
       sed [-Ealn] [-i extension] [-e script] ... [-f script_file] ... [file ...]
sed: /usr/bin/sed,
cut: illegal option -- -
usage: cut -b list [-n] [file ...]
       cut -c list [file ...]
       cut -f list [-s] [-d delim] [file ...]
cut: /usr/bin/cut,
basename: illegal option -- -
usage: basename string [suffix]
       basename [-a] [-s suffix] string [...]
basename: /usr/bin/basename,
rm: illegal option -- -
usage: rm [-f | -i] [-dPRrvW] file ...
       unlink file
rm: /bin/rm,
mkdir: illegal option -- -
usage: mkdir [-pv] [-m mode] directory ...
mkdir: /bin/mkdir,
xargs: illegal option -- -
usage: xargs [-0opt] [-E eofstr] [-I replstr [-R replacements]] [-J replstr]
             [-L number] [-n number [-x]] [-P maxprocs] [-s size]
             [utility [argument ...]]
xargs: /usr/bin/xargs,
nvm current: v11.1.0
which node: $NVM_DIR/versions/node/v11.1.0/bin/node
which iojs: iojs not found
which npm: $NVM_DIR/versions/node/v11.1.0/bin/npm
npm config get prefix: $NVM_DIR/versions/node/v11.1.0
npm root -g: $NVM_DIR/versions/node/v11.1.0/lib/node_modules

For now I got around it by wrapping nvm sourcing into a function and calling it when I need node access, since I don't need it often.

nvmi() {
  export NVM_DIR="$HOME/.nvm"
  [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm
  [ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"  # This loads nvm bash_completion
}

[[ -n "$NVM_INIT" ]] && nvmi

But I think this needs to be looked in. I know 2s is not a big deal but still, from 0.3 to 2.4 is quite a delay.

@n1kk the cause continues to be largely the same; anything that calls into nvm use (like nvm auto) also calls into nvm_die_on_prefix, which calls into npm config get prefix, and invoking npm config is slow.

@Nick011 nvm is not supported via homebrew (the homebrew formula says this when you install it). If you brew uninstall nvm, and then install it properly via the curl script in the readme, my suspicion is that it will go much faster.

That worked for me. I did the following:

  1. Uninstalled the homebrew version of nvm.
brew uninstall nvm
  1. Installed nvm via curl as described in their README.md
curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.11/install.sh | bash
  1. Added nvm path to my .bashrc:
# ~/.bashrc
source ~/.nvm/nvm.sh --no-use

i figured out that its way faster if i source the file like this instead of the recommended way thats described in the nvm README.md.

No more delay! o/

@LeaveAirykson but then when you do nvm use, I guess you need to again wait for it. You are basically delay the delay I think, which doesn't really solve the problem...

My solution was removing the nvm_die_on_prefix function when running my .zshrc, and do the sourcing and the nvm use async using zsh-async

perl -i -p0e 's/(\n(nvm_die_on_prefix)\(\) ?\{)[^}].+?\n\}/$1."}"/seg' $NVM_DIR/nvm.sh

@yxliang01 damn, you're right. i was a little bit too eager. But actually, at least in my case, if i omit the --no-use parameter, it still results in a faster load time compared to the recommended way:
```bash

still faster even without --no-use

source ~/.nvm/nvm.sh

much slower

export NVM_DIR="${XDG_CONFIG_HOME/:-$HOME/.}nvm"
[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"

If you are using the homebrew, you can reduce time about 65%.
Run brew --prefix nvm command and use result as static path in the related source command.

for example:

$ brew --prefix nvm
/usr/local/opt/nvm

edit line below in ~/.bash_profile file (or any other file which you already used for sourcing NVM)
source $(brew --prefix nvm)/nvm.sh
as this
source /usr/local/opt/nvm/nvm.sh

Detail:
the --prefix operation of the brew is already known as slow and it is even slower for nvm:

$ time  echo $(brew --prefix nvm)
/usr/local/opt/nvm

real    0m1.649s
user    0m0.790s
sys 0m0.468s

and sourcing nvm itself is much faster (but still slow):

$ time . /usr/local/opt/nvm/nvm.sh

real    0m0.917s
user    0m0.614s
sys 0m0.399s

so the result is very bad as:

$ time . $(brew --prefix nvm)/nvm.sh

real    0m2.526s
user    0m1.373s
sys 0m0.850s

so we can reduce sourcing time about %65 by omitting brew --prefix nvm in the source command.

My solution was removing the nvm_die_on_prefix function when running my .zshrc, and do the sourcing and the nvm use async using zsh-async

perl -i -p0e 's/(\n(nvm_die_on_prefix)\(\) ?\{)[^}].+?\n\}/$1."}"/seg' $NVM_DIR/nvm.sh

Could you please elaborate on the steps used to accomplish this?

I also had this problem, which rendered my shell incredibly slow. I switched to the nvm-ng hard fork, important to note is, I did see improvements immediately, but to have no load time at all actually you need to add the flag --fast-reuse. Did not found that in the docs, but is mentioned in the issue here https://github.com/wzrdtales/nvm-ng/issues/2 . Should someone have the same problem.

Is there any chance that the changes are being merged at some point from this hard fork? It is almost as fast as having a shell without nvm at all, but without deferring something, like suggested here often. Deferring is absolutely not an option for me, since I use node all the time and not just sometimes and I don't want to call a call to nvm just because I opened another shell tile.

@seyedmmousavi nvm should not be installed with brew - it’s not supported via that mechanism.

If you remove nvm_die_on_prefix, make sure you don’t have the “prefix” npm config set anywhere.

@zamgill I'm using zsh-nvm and zsh-async in this code:

step_load_nvm() {
    # remove slow and unnecessary checks for me
    perl -i -p0e 's/(\n(nvm_die_on_prefix)\(\) ?\{)[^}].+?\n\}/$1."}"/seg' $NVM_DIR/nvm.sh
    # disable version output
    sed -i '/#/!s/\(nvm_echo "Found\)/# \1/g' $NVM_DIR/nvm.sh
    # source nvm
    source $NVM_DIR/nvm.sh
    # call zsh-nvm auto use
    _zsh_nvm_auto_use
}

async_start_worker setup_worker -n
async_register_callback setup_worker step_load_nvm
async_job setup_worker sleep .1

@ypconstante do you really find nvm_ensure_version_installed to be slow? If so, i'd love a separate issue for that; since that isn't calling out to npm, i actually could make that faster.

I think I disabled it just because of this comment in the code, I tested without removing the function and it didn't slow down the startup. I edited the code so it doesn't disable nvm_ensure_version_installed.

I measured that simply changing $HOME to ~ drastically reduces the startup time.

EDIT: the previous code without eval prevented the ~ from expanding and loading nvm correctly. But the usage of ~ and eval still loads nvm and appears to be more efficient.

# .bashrc
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"                    # nvm
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"  # nvm bash_completion
~ $ time source .bashrc

real    0m0,446s
user    0m0,405s
sys 0m0,094s

Versus

# .bashrc
export NVM_DIR="~/.nvm"
eval [ -s "$NVM_DIR/nvm.sh" ] && eval \. "$NVM_DIR/nvm.sh"                    # nvm
eval [ -s "$NVM_DIR/bash_completion" ] && eval \. "$NVM_DIR/bash_completion"  # nvm bash_completion
~ $ time source .bashrc

real    0m0,114s
user    0m0,109s
sys 0m0,015s

@lucaspar ooh, that's very interesting; i believe that we use $HOME tho because ~ doesn't work on all shells. Perhaps we could runtime-detect if ~ works in the install script, and choose which to use based on that?

Very easy fix:

Replace nvm stuff in ~/.bashrc with

export NVM_DIR="$HOME/.nvm"
nvm_load () {
  . $NVM_DIR/nvm.sh
  . $NVM_DIR/bash_completion
}
alias node='unalias nvm; unalias node; unalias npm; nvm_load; node $@'
alias npm='unalias nvm; unalias node; unalias npm; nvm_load; npm $@'
alias nvm='unalias nvm; unalias node; unalias npm; nvm_load; nvm $@'

You won't get bash completion until after running nvm the first time in the current shell, but otherwise, it's a seamless solution until someone looks into why nvm is so dang slow.

@pauldraper it's already known why it's slow - because nvm use calls into npm config get prefix, and that is slow.

After reading several ideas to work around the issue, I came up with the following:

if command -v brew >/dev/null 2>&1 ; then
    #brewPrefix=$(brew --prefix) # an ok delay not as much as $(brew --prefix nvm) but still
    brewPrefix=/usr/local
fi
if [ -f /etc/bash_completion ]; then
    . /etc/bash_completion
fi
if [ -n "$brewPrefix" ] && [ -f $brewPrefix/etc/bash_completion ]; then
    . $brewPrefix/etc/bash_completion
fi
if [ -n "$brewPrefix" ] && [ -f $brewPrefix/opt/nvm/nvm.sh ]; then
    nvmInit() {
        export NVM_DIR="$HOME/.nvm"
        . $brewPrefix/opt/nvm/nvm.sh --no-use
        nvm use default >/dev/null
    }
    nvmInitBefore() {
        # create a function for every given command
        for cmd in "$@"; do
            eval "$cmd() { unset -f $* ; nvmInit ; $cmd \$@ ; }"
        done
    }
    nvmInitBefore nvm node npm yarn ncu # gulp grunt webpack markdown-pdf ...
fi

This approach is fast like others. Note, I also do not use $(brew --prefix nvm) because I can confirm this adds some smaller delay to the shell start. I also found that using functions instead of using aliases allows bash_completion to work even before the first run of a command, though it is slower than after the first run. Splitting . nvm.sh into two commands . nvm.sh --no-use+nvm use default helped fixing an issue with bash_completion of npm -+TAB+TAB.

To see the result of nvmInitBefore enter:

type node npm yarn

Do note that homebrew is explicitly unsupported, and nobody should use brew to install nvm.

Do note that home few is explicitly unsupported

But this issue has nothing to do with homebrew as far as I understand it.

nobody should use brew to install nvm.

What should anybody use then? Besides, it works quite well.

@ljharb Do you have (a link to) an explanation for what the problem with homebrew+nvm is?

@craftey many users have claimed that their performance problem goes away when they remove their brew-installed node and nvm.

The only thing you should use to install nvm is the install command in the readme - i will not fix any bugs or provide any support to someone who has installed nvm in any other way. Specifically, the brew formula will not preserve your node versions as you update nvm; in general, you should never install software via an unofficial distribution mechanism. node is only distributed from their website (nvm installs from there), and nvm is only distributed via the install command.

Specifically, the brew formula will not preserve your node versions as you update nvm

This it not my experience. Nvm via brew works quite well on my machine. Last update of nvm seemingly took place on 14. Jan 2019 to version 0.34.0. The node versions in ~/.nvm/versions/node/ are all in good shape as far as I can see. My projects build all well with different node versions.

Anyway I ll keep in mind that it is not the recommended way, for whatever reason. (Background info still welcome.)

EDIT: I have re-read the instructions from brew info nvm now. It clearly states:

You can set $NVM_DIR to any location, but leaving it unchanged from
/usr/local/opt/nvm will destroy any nvm-installed Node installations
upon upgrade/reinstall.

If the users do not set NVM_DIR they will run into the described behavior. I can understand that you do not like to support confusion coming from 3rd party installers. And brew info nvm also states that:

Please note that upstream has asked us to make explicit managing
nvm via Homebrew is unsupported by them and you should check any
problems against the standard nvm install method prior to reporting.

So I guess if I know what I am doing I am fine with homebrew.

Not as far as I’m concerned :-) but if you want to use software in a manner explicitly discouraged by its maintainer, you’re certainly free to do so.

I've got a pretty simple solution (which I used to sdkman too and it worked) which is:

export NVM_DIR="$HOME/.nvm"
nvm() {
    echo "Lazy loading nvm..."
    [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"  # This loads nvm
    [ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"  # This loads nvm bash_completion
    nvm
}

I didn't need to make any control with variables if nvm alias was executed or not because the nvm scripts will override my alias :)

@dowglaz this has been brought up multiple times; this means you won't get bash completion or access to globally installed binaries in the default node version until after first invoking nvm; also, your version doesn't pass arguments along, so the first nvm anything won't run "anything", it'll just print the help.

Hi @ljharb, thank for your observation!

  1. Ok, it doesn't bother me more than a slow shell loading every time I need it. Actually, I don't use node more than I load a shell.
  2. Thank you for the observation. I did a quick fix to pass $@ and it works fine in the first time I run.

I just shared a simpler solution, but if it's flooding the conversation, sorry.
Is there a prevision to put a fix for it in the next versions?

Since the cause is npm config get prefix is slow, there's not really any "fix" to be had. If I remove the check, users will use nvm with a prefix, and I'll get flooded with bug reports again; If I attempt to replicate the logic, I'll miss some edge cases, and it'll be hard to debug them.

Not sure if this helps or just adds noise, but I found this pull request for Microsoft VSCode:
https://github.com/Microsoft/vscode/pull/41479/files

I don't know if it has been posted yet or not, but

export NVM_DIR="$HOME/.nvm"
nvm() {
    echo "Lazy loading nvm..."
    [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"  # This loads nvm
    [ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"  # This loads nvm bash_completion

    nvm $*
}

adding the $* just executes nvm with whatever args were passed to the lazy load function. Tested in ZSH but this seems to be a Bash feature.

I don't know if it has been posted yet or not, but

export NVM_DIR="$HOME/.nvm"
nvm() {
    echo "Lazy loading nvm..."
    [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"  # This loads nvm
    [ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"  # This loads nvm bash_completion

    nvm $*
}

adding the $* just executes nvm with whatever args were passed to the lazy load function. Tested in ZSH but this seems to be a Bash feature.

That's a really nice solution, thanks for posting that!

@lucaspar i am afraid your recommendation of switching from $HOME to ~ is not working (at least on mac) - execution is faster, but environment does not get set properly:

$ node --version
-bash: node: command not found
$ export NVM_DIR="~/.nvm"
$ eval [ -s "$NVM_DIR/nvm.sh" ] && time eval \. "$NVM_DIR/nvm.sh"

real    0m0.035s
user    0m0.020s
sys 0m0.014s
$ node --version
-bash: node: command not found

now, using ~ without quotes (same slow as when using $HOME):

$ export NVM_DIR=~/.nvm
$ eval [ -s "$NVM_DIR/nvm.sh" ] && time eval \. "$NVM_DIR/nvm.sh"

real    0m0.533s
user    0m0.347s
sys 0m0.200s
$ node --version
v11.10.1

Same on Zshell. Startup got noticeably slower.

I've added lazy loading nvm, which sped up the startup:

export NVM_DIR="$HOME/.nvm"
mkdir -p "$NVM_DIR"
nvm() {
    echo "Lazy loading nvm..."
    # Remove nvm function
    unfunction "$0"
    # Load nvm
    [ -s "$NVM_DIR/nvm.sh" ] && source "$NVM_DIR/nvm.sh"
    # Load bash_completion
    [ -s "$NVM_DIR/bash_completion" ] && source "$NVM_DIR/bash_completion"
    # Call nvm
    $0 "$@"
}

This will only do the lazy loading on the first call.

In bash(1) you'd replace unfunction "$0" with unset -f "$0".

@grubyak you're right, it was not setting it correctly, that's why it's so much faster :sweat_smile:

What's working for me instead is using the lazy loading suggested by @pauldraper . I repaste it below:

# nvm
export NVM_DIR="$HOME/.nvm"
 nvm_load () {
   . $NVM_DIR/nvm.sh
   . $NVM_DIR/bash_completion
 }
 alias node='unalias nvm; unalias node; unalias npm; nvm_load; node $@'
 alias npm='unalias nvm; unalias node; unalias npm; nvm_load; npm $@'
 alias nvm='unalias nvm; unalias node; unalias npm; nvm_load; nvm $@'

The only inconvenience for me is the need to run node, nvm, or npm before any global package (the ones installed with npm install -g <package>), otherwise the command is not recognized.

@lucaspar here is a version which will work for all global packages: https://www.reddit.com/r/node/comments/4tg5jg/lazy_load_nvm_for_faster_shell_start/d5ib9fs/

Since the cause is npm config get prefix is slow, there's not really any "fix" to be had. If I remove the check, users will use nvm with a prefix, and I'll get flooded with bug reports again; If I attempt to replicate the logic, I'll miss some edge cases, and it'll be hard to debug them.

How would you feel about adding a way for advanced users to bypass this test. Maybe by setting an environment variable, something like NVM_SKIP_PREFIX_CHECK or NVM_I_PROMISE_NOT_TO_CONFIGURE_AN_NPM_ALIAS?

Another way to prevent the bogus bug reports might be to add the check to nvm debug and print an obvious error message with instructions for deleting the prefix, similar to what nvm use is currently doing.

I definitely like the idea of adding a check to nvm debug; a PR to do that would be greatly appreciated.

What about adding an advanced way to override the check in nvm use?

I'd prefer not to; it'll just end up in a copy-pasted SO answer and defeat the purpose of having the check in the first place.

@Leandros suggested the following solution
https://www.reddit.com/r/node/comments/4tg5jg/lazy_load_nvm_for_faster_shell_start/d5ib9fs/

Just added the yarn global support to the original script

declare -a NODE_GLOBALS_NPM=(`find $HOME/.nvm/versions/node -maxdepth 3 -type l -wholename '*/bin/*'`)
declare -a NODE_GLOBALS_YARN=(`find $HOME/.yarn/bin -maxdepth 3 -type l -wholename '*/bin/*'`)
declare -a NODE_GLOBALS=(`echo $NODE_GLOBALS_NPM $NODE_GLOBALS_YARN | xargs -n1 basename | sort | uniq`)
NODE_GLOBALS+=("node")
NODE_GLOBALS+=("nvm")

load_nvm () {
    export NVM_DIR=~/.nvm
    [ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"
    export NODE_PATH="$NVM_BIN"
}

for cmd in "${NODE_GLOBALS[@]}"; do
    eval "${cmd}(){ unset -f ${NODE_GLOBALS}; load_nvm; ${cmd} \$@ }"
done

# Add yarn bin
export PATH=$PATH:$HOME/.yarn/bin

You don’t need (shouldn’t have) the yarn ones, because nvm doesn’t add that to the PATH when loaded normally.

Unfortunately without checking the yarn global folder, the installed yarn global commands wouldn't trigger load_nvm.

You can install global packages with npm i -g some-package and you can install with yarn global add other-package. Yarn places the global commands in ~/.yarn/bin, so have to check both folder to get the full collection of global commands.

Global commands will be placed as follow:

npm i -g some-package -> ~/.nvm/versions/node/v10.15.3/bin/some-package
yarn global add other-package -> ~/.yarn/bin/other-package

Hi, I found a good solution at https://www.growingwiththeweb.com/2018/01/slow-nvm-init.html it works fine for me.

Something I have in my .bash_profile that solves the problem partly is:

[ ! -r ~/.nvm/nvm.sh ] || {
    function nvm() {
        unset -f nvm node npm
        . ~/.nvm/nvm.sh
        nvm use node >/dev/null
        [ ! -r ~/.nvm/bash_completion ] || . ~/.nvm/bash_completion
        nvm ${1+"$@"}
    }

    function node() {
        nvm --version >/dev/null 2>&1
        node ${1+"$@"}
    }

    function npm() {
        nvm --version >/dev/null 2>&1
        npm ${1+"$@"}
    }
}

It makes nvm, node and npm lazy functions, so that NVM is only loaded the first time one of them is called.

It has its problems, tho. Those are shell functions, so scripts with a #!/usr/bin/env node shebang for instance will complain about not finding node (or, worse, use the system node install if present).

@jcayzac additionally, globally installed binaries in your default node version won't be available prior to running node/nvm/npm.

I've switched to --no-use for the time being. While not ideal, it's the best compromise for me right now (I don't have a system node install so anything using node will complain and remind me to type nvm use).

FWIW here's what's in my .bash_profile now:

# Source "nvm" but don't use any version yet
[ ! -r ~/.nvm/nvm.sh ] || {
  . ~/.nvm/nvm.sh --no-use

  # Call "nvm use" when entering a directory with a .nvmrc
  __jc_nvmrc_probe_dir=
  function __jc_nvmrc_probe() {
    [[ "$__jc_nvmrc_probe_dir" == "$PWD" ]] || [ ! -r .nvmrc ] || {
      __jc_nvmrc_probe_dir="$PWD"
      nvm use
    }
  }
  [[ "$PWD" == "$HOME" ]] || __jc_nvmrc_probe
  PROMPT_COMMAND="__jc_nvmrc_probe${PROMPT_COMMAND+;$PROMPT_COMMAND}"
}

The simplest solution I've found:

DEFAULT_NODE_VERSION='8.14.1'

# Ensure we have a default node version in our PATH at startup
if [ -d "${HOME}/.nvm/versions/node/v${DEFAULT_NODE_VERSION}/bin" ] ; then
  PATH="${HOME}/.nvm/versions/node/v${DEFAULT_NODE_VERSION}/bin:${PATH}"
fi

# Avoid using the slow `nvm use` at startup.
# We already have a default node available in our PATH.
[[ -s "$NVM_DIR/nvm.sh" ]]          && source "$NVM_DIR/nvm.sh" --no-use

(Change DEFAULT_NODE_VERSION to be whatever version of node you want to use when bash starts up. Make sure it is installed via nvm using nvm install ${NODE_DEFAULT_VERSION})

@Asheq while this works, it's brittle (if nvm changes) and it avoids the important bugfix that makes nvm use slow - ensuring that npm config get prefix isn't set.

While we're waiting on npm to figure out how they're gonna refactor their config logic, I'll put forth the solution I'm happiest with after hacking on this on/off the past few days, reading everyone's suggestions:

export NVM_DIR="$HOME/.nvm"
[ -s "/usr/local/opt/nvm/etc/bash_completion" ] && . "/usr/local/opt/nvm/etc/bash_completion"
export PATH="$NVM_DIR/versions/node/v$(<$NVM_DIR/alias/default)/bin:$PATH"
alias nvm="unalias nvm; [ -s "/usr/local/opt/nvm/nvm.sh" ] && . "/usr/local/opt/nvm/nvm.sh"; nvm $@"

This way node is available in my PATH right away (necessary for my dev web server start that uses yarn), and nvm is there when I need it. Also don't need to keep a specific version number in my shell config (as long as you've set a default alias in nvm). FWIW, bash completion takes no noticeable time, so it's not necessary to lazy load it.

https://gist.github.com/gfguthrie/9f9e3908745694c81330c01111a9d642

The directory in the last line can be replaced with $NVM_DIR:

export NVM_DIR="$HOME/.nvm"
[ -s "/usr/local/opt/nvm/etc/bash_completion" ] && . "/usr/local/opt/nvm/etc/bash_completion"
export PATH="$NVM_DIR/versions/node/v$(<$NVM_DIR/alias/default)/bin:$PATH"
alias nvm="unalias nvm; [ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"; nvm $@"

When default is set to node, the PATH setting does not work. An alternative to set to the latest node

export PATH="$NVM_DIR/versions/node/$(ls $NVM_DIR/versions/node | sort -V | tail -n1)/bin:$PATH"

An alternative approach is to use nodebrew instead of nvm. It starts up a lot faster. https://github.com/hokaccha/nodebrew

The directory in the last line can be replaced with $NVM_DIR:

It certainly can if that is your setup. I keep nvm installed separate from NVM_DIR.

export PATH="$NVM_DIR/versions/node/$(ls $NVM_DIR/versions/node | sort -V | tail -n1)/bin:$PATH"

That is pretty neat! Not for me, but I like it!

@gfguthrie note that nvm does not support any setup where nvm.sh is not located inside $NVM_DIR.

Try powerlevel10k, it has instant prompt feature to make you be confident to type command without weird duplication, while plugins such as nvm load in the background.
https://github.com/romkatv/powerlevel10k#instant-prompt

While we're waiting on npm to figure out how they're gonna refactor their config logic, I'll put forth the solution I'm happiest with after hacking on this on/off the past few days, reading everyone's suggestions:

export NVM_DIR="$HOME/.nvm"
[ -s "/usr/local/opt/nvm/etc/bash_completion" ] && . "/usr/local/opt/nvm/etc/bash_completion"
export PATH="$NVM_DIR/versions/node/v$(<$NVM_DIR/alias/default)/bin:$PATH"
alias nvm="unalias nvm; [ -s "/usr/local/opt/nvm/nvm.sh" ] && . "/usr/local/opt/nvm/nvm.sh"; nvm $@"

This way node is available in my PATH right away (necessary for my dev web server start that uses yarn), and nvm is there when I need it. Also don't need to keep a specific version number in my shell config (as long as you've set a default alias in nvm). FWIW, bash completion takes no noticeable time, so it's not necessary to lazy load it.

https://gist.github.com/gfguthrie/9f9e3908745694c81330c01111a9d642

Note that brew-installed nvm changed the location of bash completion script. I also have to source the completion script after nvm is sourced.

alias nvm="unalias nvm; [ -s "/usr/local/opt/nvm/nvm.sh" ] && . "/usr/local/opt/nvm/nvm.sh"; [ -s "/usr/local/opt/nvm/etc/bash_completion.d/nvm" ] && . "/usr/local/opt/nvm/etc/bash_completion.d/nvm"; nvm $@"

@frankyjuang also note that nvm explicitly does not support installation with homebrew, and the formula itself warns of this. The only proper way to install nvm is the curl/wget command in the readme.

I use this solution:

https://www.reddit.com/r/node/comments/4tg5jg/lazy_load_nvm_for_faster_shell_start/d5ib9fs/

Works well on zsh. For some reason, on bash I get some errors.

The directory in the last line can be replaced with $NVM_DIR:

export NVM_DIR="$HOME/.nvm"
[ -s "/usr/local/opt/nvm/etc/bash_completion" ] && . "/usr/local/opt/nvm/etc/bash_completion"
export PATH="$NVM_DIR/versions/node/v$(<$NVM_DIR/alias/default)/bin:$PATH"
alias nvm="unalias nvm; [ -s $NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"; nvm $@"

@char101 is there a typo in the last line?

i think there's a missing " in [ -s $NVM_DIR/nvm.sh" ]

the last line should be:

alias nvm="unalias nvm; [ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"; nvm $@"

thank you otherwise!! very useful.

@char101 is there a typo in the last line?

Thank you for the correction, the missing quote has been added.

export PATH="$NVM_DIR/versions/node/v$(<$NVM_DIR/alias/default)/bin:$PATH"

It does not work for me because it has an additional v, which gives me this in my $PATH: /home/xxxx/.nvm/versions/node/vv10.22.0/bin. I had to remove the v:

export PATH="$NVM_DIR/versions/node/$(<$NVM_DIR/alias/default)/bin:$PATH"

@ledenis the alias is not supposed to include the v; did you use nvm commands to make the alias, or did you do it manually?

For anyone not managing to get it work properly, I recommend n.

@ljharb Ah, I see. But this still works well with the v in the alias. I set it via nvm with this command:

nvm alias default v10.22.0

(I actually copy/pasted the version v10.22.0 from nvm ls-remote command)

So I have:

cat $NVM_DIR/alias/default
v10.22.0
nvm ls
->     v10.22.0
       v12.18.3
default -> v10.22.0
node -> stable (-> v12.18.3) (default)
stable -> 12.18 (-> v12.18.3) (default)
iojs -> N/A (default)
unstable -> N/A (default)
lts/* -> lts/erbium (-> v12.18.3)
lts/argon -> v4.9.1 (-> N/A)
lts/boron -> v6.17.1 (-> N/A)
lts/carbon -> v8.17.0 (-> N/A)
lts/dubnium -> v10.22.0
lts/erbium -> v12.18.3

@ledenis ah, right - it's because these are workarounds that aren't officially supported and don't work properly with nvm :-D

this code snippet has really used my startup time while ensuring that I also have access to global packages as well as yarn globals and yarn project have same node env version.
```zsh
export NVM_DIR="$HOME/.nvm"

[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" # This loads nvm

[ -s "$NVM_DIR/bash_completion" ] && . "$NVM_DIR/bash_completion" # This loads nvm bash_completion

NODE_GLOBALS=(find ~/.nvm/versions/node -maxdepth 3 -type l -wholename '*/bin/*' | xargs -n1 basename | sort | uniq)
NODE_GLOBALS+=(node nvm yarn)

_load_nvm() {
[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"
[ -s "$NVM_DIR/bash_completion" ] && . "$NVM_DIR/bash_completion" # This loads nvm bash_completion
}

for cmd in "${NODE_GLOBALS[@]}"; do
eval "function ${cmd}(){ unset -f ${NODE_GLOBALS[*]}; _load_nvm; unset -f _load_nvm; ${cmd} $@; }"
done
unset cmd NODE_GLOBALS

export PATH="$PATH:$HOME/.yarn/bin"```

fastest solution is to cache the env variables

#!/bin/bash
# nvm-env-cached.sh
# this file is auto-generated on every nvm state change

NVM_DIR=/home/user/.nvm
NVM_CD_FLAGS=
NVM_BIN=/home/user/.nvm/versions/node/v14.5.0/bin

p=/home/user/.nvm/versions/node/v14.5.0/bin
if [[ ":$PATH:" != *":$p:"* ]]
then
  PATH="$p:$PATH"
fi

takes 5 miliseconds to load with source nvm-env-cached.sh

who wants to implement? : D

@milahu that only works if you a) hardcode a version and b) if nvm never changes its behavior here. It's not a good idea.

thats two cheap excuses in one sentence : P

a) "this file is auto-generated on every nvm install" (or any other command that changes the nvm state, like nvm alias default)
b) when nvm changes its behavior, the cache file format is changed too

@milahu how do you achieve the autogeneration? that snippet doesn't include any autogeneration.

nvm-env-cached.sh is only the result, the generator does not exist yet, but should be rather trivial to do (write new cache file on every state change)

thats what i mean with "who wants to implement? : D"

Ah, I see what you mean, thanks for clarifying.

to maximize compatibility with non-bash-shells
the 'prepend path' code should look like

#!/bin/sh

case ":$PATH:" in
  *:"$p":*)
    ;;
  *)
    PATH="$p${PATH:+:$PATH}"
esac

which takes some nanoseconds longer to parse

nvm
Node Version Manager - POSIX-compliant bash script to manage multiple active node.js versions

For future reference, nvm supports mostly POSIX shells - ksh, dash, sh, bash, zsh in particular.

@milahu This was implemented long time ago already, together with other improvements. However it never got merged due to reasons you can read yourself, thought it might be worth mentioning. There is a hard fork which is fast and also does this caching. Here is the reasoning and the hard fork, I am using that one for very long time and didn't had any problems with it https://github.com/wzrdtales/nvm-ng/issues/2

Don't forget the --fast-reuse flag to activate this fast path.

This was implemented long time ago already, together with other improvements. However it never got merged due to reasons you can read yourself

aah, incompetent maintainers .... dont we all love that problem?

but probably he/she/it/them is 100% loyal to his 'code of conduct'
'lets all be super nice to each other, so maybe no one will notice how much we suck at coding'

Here is the reasoning and the hard fork, I am using that one for very long time and didn't had any problems with it https://github.com/wzrdtales/nvm-ng/issues/2

yes! problem solved

@milahu now that's just uncalled for and needlessly hostile, so i'll be banning you from the org and hiding your comments.

@tilsmen Careful using any forks; that one's missing over 2 years of improvements.

yes i know @ljharb but nothing really meaningful was added (for my terms, not in general don't get me wrong not trying to offend here) during this 2 years. The difference of the hard fork and your original are just two commits in the hard fork which are like a show stopper to me from your work. Everything is working with this fork also with the newest node version without any flaw and I have the benefit of not being disturbed in my workflow and still able to use my console normal. So I think it is reasonable, if you by any chance improve here the loading times let me know though.

@tilsmen luckily i'm very close to releasing a performance improvement here - i've just opened #2317. if you could try that out locally and comment on the PR with performance comparisons, that would be very helpful.

@LocalToonsHQ, What are you even talking about?! 😑

Was this page helpful?
0 / 5 - 0 ratings