Skip to content

Instantly share code, notes, and snippets.

@rcugut
Forked from DanHerbert/fix-homebrew-npm.md
Last active February 2, 2024 11:51
Show Gist options
  • Save rcugut/c7abd2a425bb65da3c61d8341cd4b02d to your computer and use it in GitHub Desktop.
Save rcugut/c7abd2a425bb65da3c61d8341cd4b02d to your computer and use it in GitHub Desktop.
Install node & npm on Mac OS X with Homebrew

DEPRECATED as of macOS 10.13 (High Sierra). See the new GUIDE to install nvm and yarn for macOS (updated July 2019)

Fixing npm On Mac OS X for Homebrew Users

Installing node through Homebrew can cause problems with npm for globally installed packages. To fix it quickly, use the solution below. An explanation is also included at the end of this document.

Solution

This solution fixes the error caused by trying to run npm update npm -g. Once you're finished, you also won't need to use sudo to install npm modules globally.

Before you start, make a note of any globally installed npm packages. These instructions will have you remove all of those packages. After you're finished you'll need to re-install them.

Run the following commands to remove all existing global npm modules, uninstall node & npm, re-install node with the right defaults, install npm as its own pacakge, and configure the location for global npm modules to be installed.

1. Re-install node without npm

# run the following commands

# this next line erases all the existing global npm packages
rm -rf /usr/local/lib/node_modules

# remove previously installed node
brew uninstall node
brew prune # clean all broken symlinks
brew update # always good to have the latest

# install node via brew, but without npm
# there are 2 options:
# - if you want to use `yarn` (yarnpkg.com), you need latest 'node'
# - if you don't use `yarn` (yarnpkg.com), prefer LTS 'node@6'

brew install node --without-npm


# install yarn (see yarnpkg.com for more info)
brew install yarn
# follow up with: https://yarnpkg.com/en/docs/install

You should now be able to run the node command

2. Prepare the npm new home: /usr/local/npm_packages

# run the following commands

mkdir -p /usr/local/npm_packages


# ONLY IF THE COMMAND ABOVE FAILS >>>
# it means the permissions are wrong with your `/usr/local` folder, so fix it;
# normally, with Homebrew, your user should own the entire `/usr/local` folder:

sudo chown -R `whoami` /usr/local

Add/append the following lines in ~/.bashrc

# this is the root folder where all globally installed node packages will  go
export NPM_PACKAGES="/usr/local/npm_packages"
export NODE_PATH="$NPM_PACKAGES/lib/node_modules:$NODE_PATH"
# add to PATH
export PATH="$NPM_PACKAGES/bin:$PATH"

And make sure you load the .bashrc in your .bash_profile:

  • IMPORTANT: make sure you do not have both a .profile and a .bash_profile; if you do, copy everything from .profile into .bash_profile and then remove the .profile
  • Check if the following or similar line exists in your .bash_profile:
[[ -s ~/.bashrc ]] && source ~/.bashrc
  • make sure .bashrc is executable
# run the following commands

chmod +x ~/.bashrc

3. Restart your iTerm / Terminal

IMPORTANT: close all existing iTerm/Terminal sessions and re-open iTerm/Terminal before going further

Advanced: or just reload the .bash_profile -- source ~/.bash_profile

3. Install npm from npmjs.com

First, set the correct npm home in ~/.npmrc

Make sure ~/.npmrc file exists, and contains a line as below:

prefix=/usr/local/npm_packages

Run the npm install script from npmjs.com

curl -L https://www.npmjs.com/install.sh | sh

NOTE @ July 13 2017: the install script from above (from npmjs.com) silently fails and doesn't copy the npm package contents correctly (see comments below from @hughsw). In order to (hack)fix this you can do the following after running the above npm install.sh script.

The instructions below apply to npm 5.2.0, but may work for earlier or later 5.x releases:

# manually download and un-targz into a local dir (it will be named `package`)
curl -L https://registry.npmjs.org/npm/-/npm-5.2.0.tgz | tar xz

# remove the broken npm symlink (generated by the nppmjs install.sh script)
rm -rf /usr/local/npm_packages/lib/node_modules/npm

# move the extracted `package` in the correct place and rename to `npm`
mv package /usr/local/npm_packages/lib/node_modules/npm

# that should do it. The bin/npm symlinks should now work

# make sure it works, and update to latest available npm:
npm install -g npm

# if you reach this step, w/o any errors =>  ALL OK!

That's it. You should now be able to run the npm command without sudo.


NEVER run npm as sudo; so never do sudo npm install ...


Explanation of the issue

If you're a Homebrew user and you installed node via Homebrew, there is a major philosophical issue with the way Homebrew and NPM work together. If you install node with Homebrew and then try to do npm update npm -g, you may see an error like this:

$ npm update npm -g
npm http GET https://registry.npmjs.org/npm
npm http 304 https://registry.npmjs.org/npm
npm http GET https://registry.npmjs.org/npm/1.4.4
npm http 304 https://registry.npmjs.org/npm/1.4.4
npm ERR! error rolling back Error: Refusing to delete: /usr/local/bin/npm not in /usr/local/lib/node_modules/npm
npm ERR! error rolling back     at clobberFail (/usr/local/Cellar/node/0.10.26/lib/node_modules/npm/lib/utils/gently-rm.js:57:12)
npm ERR! error rolling back     at next (/usr/local/Cellar/node/0.10.26/lib/node_modules/npm/lib/utils/gently-rm.js:43:14)
npm ERR! error rolling back     at /usr/local/Cellar/node/0.10.26/lib/node_modules/npm/lib/utils/gently-rm.js:52:12
npm ERR! error rolling back     at Object.oncomplete (fs.js:107:15)
npm ERR! error rolling back  [email protected] { [Error: Refusing to delete: /usr/local/bin/npm not in /usr/local/lib/node_modules/npm] code: 'EEXIST', path: '/usr/local/bin/npm' }
npm ERR! Refusing to delete: /usr/local/bin/npm not in /usr/local/lib/node_modules/npm
File exists: /usr/local/bin/npm
Move it away, and try again. 

npm ERR! System Darwin 13.1.0
npm ERR! command "/usr/local/Cellar/node/0.10.26/bin/node" "/usr/local/bin/npm" "update" "npm" "-g"
npm ERR! cwd /Users/dan/Google Drive/Projects/dotfiles
npm ERR! node -v v0.10.26
npm ERR! npm -v 1.4.3
npm ERR! path /usr/local/bin/npm
npm ERR! code EEXIST
npm ERR! 
npm ERR! Additional logging details can be found in:
npm ERR!     /Users/dan/Google Drive/Projects/dotfiles/npm-debug.log
npm ERR! not ok code 0

There's an NPM bug for this exact problem. The bug has been "fixed" by Homebrew installing npm in a way that allows it to manage itself once the install is complete. However, this is error-prone and still seems to cause problems for some people. The root of the the issue is really that npm is its own package manager and it is therefore better to have npm manage itself and its packages completely on its own instead of letting Homebrew do it.

Also, using the Homebrew installation of npm will require you to use sudo when installing global packages. Since one of the core ideas behind Homebrew is that apps can be installed without giving them root access, this is a bad idea.

@hughsw
Copy link

hughsw commented Jun 14, 2017

As of 2017-06-14 the steps above fail to install npm. It appears that the installation puts in symlinks that point into the TMP directory where the package got unpacked (and later deleted). Here are command showing the environment and the problem:

:~ hugh$ printenv|grep -i npm
PATH=/Users/hugh/bin:/usr/local/npm_packages/bin:/usr/local/opt/gnu-tar/libexec/gnubin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/X11/bin:/usr/local/opt/go/libexec/bin:/Users/hugh/work/go/bin
NODE_PATH=/usr/local/npm_packages/lib/node_modules:
NPM_PACKAGES=/usr/local/npm_packages

:~ hugh$ ls -la /usr/local/npm_packages/
total 0
drwxr-xr-x   2 hugh  admin   68 Jun 14 13:34 .
drwxr-xr-x  16 root  wheel  544 Jun 14 12:53 ..

:~ hugh$ cat ~/.npmrc
prefix=/usr/local/npm_packages
save-exact=true
progress=false

:~ hugh$ which npm

:~ hugh$ curl -L https://www.npmjs.com/install.sh | sh
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  6255  100  6255    0     0  11898      0 --:--:-- --:--:-- --:--:-- 11891
tar=/usr/local/opt/gnu-tar/libexec/gnubin/tar
version:
tar (GNU tar) 1.29
Copyright (C) 2015 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Written by John Gilmore and Jay Fenlason.
install npm@latest
fetching: https://registry.npmjs.org/npm/-/npm-5.0.3.tgz
removed 1 package in 0.066s   # presumably removing the previous failure where I wasn't carefully scripting what I typed
/usr/local/npm_packages/bin/npm -> /usr/local/npm_packages/lib/node_modules/npm/bin/npm-cli.js
+ [email protected]
added 1 package in 2.204s
It worked

:~ hugh$ which npm

:~ hugh$ ls -la /usr/local/npm_packages/
total 0
drwxr-xr-x   6 hugh  admin  204 Jun 14 13:42 .
drwxr-xr-x  16 root  wheel  544 Jun 14 12:53 ..
drwxr-xr-x   3 hugh  admin  102 Jun 14 13:42 bin
drwxr-xr-x   2 hugh  admin   68 Jun 14 13:42 etc
drwxr-xr-x   3 hugh  admin  102 Jun 14 13:42 lib
drwxr-xr-x   3 hugh  admin  102 Jun 14 13:42 share

:~ hugh$ ls -la /usr/local/npm_packages/bin
total 8
drwxr-xr-x  3 hugh  admin  102 Jun 14 13:42 .
drwxr-xr-x  6 hugh  admin  204 Jun 14 13:42 ..
lrwxr-xr-x  1 hugh  admin   38 Jun 14 13:42 npm -> ../lib/node_modules/npm/bin/npm-cli.js

:~ hugh$ ls -la /usr/local/npm_packages/bin/../lib/node_modules/npm/bin/npm-cli.js
ls: /usr/local/npm_packages/bin/../lib/node_modules/npm/bin/npm-cli.js: No such file or directory

:~ hugh$ ls -la /usr/local/npm_packages/bin/../lib/node_modules/npm/bin/
ls: /usr/local/npm_packages/bin/../lib/node_modules/npm/bin/: No such file or directory

:~ hugh$ ls -la /usr/local/npm_packages/bin/../lib/node_modules/npm/
ls: /usr/local/npm_packages/bin/../lib/node_modules/npm/: No such file or directory

:~ hugh$ ls -la /usr/local/npm_packages/bin/../lib/node_modules/
total 8
drwxr-xr-x  3 hugh  admin  102 Jun 14 13:42 .
drwxr-xr-x  3 hugh  admin  102 Jun 14 13:42 ..
lrwxr-xr-x  1 hugh  admin   88 Jun 14 13:42 npm -> ../../../../../private/var/folders/fd/7j7f85712_535yytw45h9fj80000gn/T/npm.75082/package

@fasfsfgs
Copy link

@hughsw did you manage to fix or workaround this issue?

@jhyde
Copy link

jhyde commented Jun 28, 2017

Did you ever come up with a resolution to this problem? I'm running into the exact same issue.

@hughsw
Copy link

hughsw commented Jul 7, 2017

Yes, but not the way I intended. We switched to the latest node (8.1.2) and have not had trouble with the npm (5.0.3) that came with it.

The following is taken from the instructions I wrote for our team (with some stuff redacted). You will get a newer version of node than these instructions indicate.

Notes on prepping your Mac for Angular 4

We're upgrading to Angular 4.

This is a two-step process:

  • First you need to overhaul your dev environment on your Mac. This is disruptive because many steps are necessary, and node and npm are out of action for the duration.
  • Then you switch to a project configuration that uses Angular 4. This is relatively simple

Before removing tools

Before removing tools, be sure to shut down any instances of npm that you may be running in terminals/shells for the service or the server.

Grep for npm to verify that it's not running.

Example of a Verification Failure: you should not see any npm processes:

$ ps ax | fgrep npm
  848 s002  S+     0:00.30 npm   # npm running a server somewhere...
  843 s003  S+     0:00.37 npm   # npm running a server somewhere...
 6315 s006  R+     0:00.00 fgrep npm

Verification Success: you should only see the fgrep process

$ ps ax | fgrep npm
 6317 s006  S+     0:00.00 fgrep npm

Get rid of old versions of tools

Remove stuff and verify that it's gone.

Look at what Yarn has installed globally (your list will be different).

Note: You must use yarn global ... for managing globally installed packages.

$ yarn global ls
warning No license field
info "@angular/[email protected]" has binaries:
   - ng
info "[email protected]" has binaries:
   - node-gyp
info "[email protected]" has binaries:
   - node-pre-gyp
info "[email protected]" has binaries:
   - nodemon
✨  Done in 3.71s.

Remove all yarn-managed packages

Use the first part of the package name following "info" for the package name:

$ yarn global remove nodemon
[1/2] Removing module nodemon...
[2/2] Regenerating lockfile and installing missing dependencies...
warning No license field
success Uninstalled packages.
✨  Done in 5.46s.
$ yarn global remove node-pre-gyp
[1/2] Removing module node-pre-gyp...
[2/2] Regenerating lockfile and installing missing dependencies...
warning No license field
success Uninstalled packages.
✨  Done in 5.25s.
$ yarn global remove node-gyp
[1/2] Removing module node-gyp...
[2/2] Regenerating lockfile and installing missing dependencies...
warning No license field
success Uninstalled packages.
✨  Done in 5.33s.
$ yarn global remove @angular/cli
[1/2] Removing module @angular/cli...
[2/2] Regenerating lockfile and installing missing dependencies...
warning No license field
success Uninstalled packages.
✨  Done in 2.33s.

Verify that they're all gone, and that there's no binary (Yarn's or anyone else's around)

$ yarn global ls
warning No license field
✨  Done in 0.08s.

$ ng
-bash: ng: command not found

$ nodemon
-bash: /Users/hugh/.config/yarn/global/node_modules/.bin/nodemon: No such file or directory

I don't know why my two failure messages for ng vs nodemon are so different.

If you still have packages listed, or you still have a version of either ng or nodemon available, you will have to figure out why and get rid of them all. Regarding binaries, friends include:

$ which ng
$ which nodemon

Remove tools that npm manages

You may have tools globally installed and managed by npm. See if npm is managing tools:

$ npm list -g --depth=0
/usr/local/lib
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
└── [email protected]

If you have tools in a tree as above, you have to remove each of them with npm. Remove each tool, except npm itself. E.g.

npm uninstall angular-cli -g
npm uninstall mysql -g
npm uninstall nodemon -g
npm uninstall sequelize -g
npm uninstall sequelize-cli -g

Once npm list -g --depth=0 only shows npm itself, then remove npm:

npm uninstall npm -g

Remove tools from Brew

Remove node (and npm which it includes), yarn, and watchman from your Brew installation

$ brew ls yarn watchman node
/usr/local/Cellar/yarn/0.24.6/bin/yarn
/usr/local/Cellar/yarn/0.24.6/bin/yarnpkg
/usr/local/Cellar/yarn/0.24.6/libexec/bin/ (5 files)
/usr/local/Cellar/yarn/0.24.6/libexec/lib/ (2 files)
/usr/local/Cellar/yarn/0.24.6/libexec/package.json
/usr/local/Cellar/watchman/4.7.0/bin/watchman
/usr/local/Cellar/watchman/4.7.0/bin/watchman-make
/usr/local/Cellar/watchman/4.7.0/bin/watchman-wait
/usr/local/Cellar/watchman/4.7.0/libexec/bin/ (3 files)
/usr/local/Cellar/watchman/4.7.0/libexec/lib/ (11 files)
/usr/local/Cellar/watchman/4.7.0/share/doc/watchman-4.7.0/README.markdown
/usr/local/Cellar/node/8.1.2/bin/node
/usr/local/Cellar/node/8.1.2/etc/bash_completion.d/npm
/usr/local/Cellar/node/8.1.2/include/node/ (135 files)
/usr/local/Cellar/node/8.1.2/lib/dtrace/node.d
/usr/local/Cellar/node/8.1.2/libexec/bin/npm
/usr/local/Cellar/node/8.1.2/libexec/lib/ (3632 files)
/usr/local/Cellar/node/8.1.2/share/doc/ (3 files)
/usr/local/Cellar/node/8.1.2/share/man/man1/node.1
/usr/local/Cellar/node/8.1.2/share/systemtap/tapset/node.stp

Also run this:

$ brew ls npm

If the above command shows that you have npm intalled and managed by Brew, then you should include npm in the following commands that remove stuff; insert "npm" right before "node" in these commands.

$ brew uninstall yarn watchman  node
Uninstalling /usr/local/Cellar/yarn/0.24.6... (13 files, 3.4MB)
Uninstalling /usr/local/Cellar/watchman/4.7.0... (21 files, 428.9KB)
Uninstalling /usr/local/Cellar/node/8.1.1... (3,786 files, 45.9MB)

Verify that all of yarn, watchman, npm, and node are gone:

$ for p in yarn watchman node ; do brew ls $p ; done
Error: No such keg: /usr/local/Cellar/yarn
Error: No such keg: /usr/local/Cellar/watchman
Error: No such keg: /usr/local/Cellar/node

$ yarn
-bash: /usr/local/bin/yarn: No such file or directory

$ watchman
-bash: watchman: command not found

$ npm
env: node: No such file or directory

$ node
-bash: node: command not found

If you still have any of those commands available, you will have to figure out why and get rid of them all.

Install up-to-date tools

Update and Upgrade Brew

$ brew update   # be patient
...

$ brew upgrade   # be (very) patient
...

Do the above two commands again, just to be sure (it shouldn't take long).

Install node (and npm)

$ brew install node
==> Downloading https://homebrew.bintray.com/bottles/node-8.1.2.sierra.bottle.tar.gz
Already downloaded: /Users/hugh/Library/Caches/Homebrew/node-8.1.2.sierra.bottle.tar.gz
==> Pouring node-8.1.2.sierra.bottle.tar.gz
==> Using the sandbox
==> Caveats
Bash completion has been installed to:
  /usr/local/etc/bash_completion.d
==> Summary
 /usr/local/Cellar/node/8.1.2: 3,782 files, 45.9MB

Verify:

$ which node
/usr/local/bin/node
$ node --version
v8.1.2

$ which npm
/usr/local/bin/npm
$ npm --version
5.0.3

@hughsw
Copy link

hughsw commented Jul 7, 2017

Also, just today, I did an uninstall of the node that was installed via my above instructions. After the uninstall, it left npm installed, but unable to run due to there not being a node available. (I'm not sure if this is a manifestation of the original problem that this thread addresses).

The reason for the uninstall is that I was downgrading to node@6. The install of node@6 configured itself to not install a new npm. And now the orphan npm works using the node@6 that I installed. So, I now have node 6.11.0 and npm 5.0.3 (where the npm 5.0.3 was installed as part of node 8.1.2, but not removed when I uninstalled node 8).

@rcugut
Copy link
Author

rcugut commented Jul 13, 2017

True, there is a problem with the latest install of npm (probably >= 5.0). I stumbled over this today, with a fresh install.

I ended up hack-fixing this by manually copying the untarred contents of the npm tgz in /usr/local/npm_packages/node_modules/npm

I did an update to the gist above, to reflect this extra step.

Eventually, the initial issue that lead to this guide may have disappeared (i.e. fixed), and now it may work to install node with npm bundled, directly via homebrew. I didn't have time to give it a try.

@andredewaard
Copy link

andredewaard commented Dec 27, 2017

This doesn't work on High Sierra.

mkdir -p /usr/local/npm_packages outputs: mkdir: /usr/local/npm_packages: Permission denied
and
sudo chown -R `whoami` /usr/local outputs: chown: /usr/local: Operation not permitted

Saw something similar on Homebrew/brew#3228 (comment)

@jevgen
Copy link

jevgen commented Jan 8, 2018

You may need to fix permissions
sudo chown -R $(whoami) /usr/local/share/doc
before install.

@ran-dall
Copy link

I've been using this walkthrough for a while...
https://johnpapa.net/how-to-use-npm-global-without-sudo-on-osx/

@suvajit
Copy link

suvajit commented Jan 24, 2018

FInally my node/npm got resolved after much struggle !!
Thanks to your very well described process with proper anecdotes.

@SilencerWeb
Copy link

it doesn't work for me =( in the end when I'm trying to use npm install -g npm I have such error zsh: command not found: npm

@nolybom
Copy link

nolybom commented Mar 28, 2018

To fix the owner on high sierra run this...

sudo chown -R $(whoami) $(brew --prefix)/*

@MirelesCloud
Copy link

You're my hero. I've spent all day trying to get npm working. This finally worked. However, note that this step # move the extracted package in the correct place and rename to npm
mv package /usr/local/npm_packages/lib/node_modules/npm
turned out the following error
mv: rename package to /usr/local/npm_packages/lib/node_modules/npm: No such file or directory
I haven't been able to fix this.

@vukanac
Copy link

vukanac commented Apr 5, 2018

List and save if you need all previous packages (won't work if you have already removed node):

$ npm list -g

Remove global packages:
$ rm -rf /usr/local/lib/node_modules
$ rm -rf ~/.npm-packages/lib/node_modules/npm

Then just install node (latest) (with npm) with brew:
$ brew install node
$ node -v
$ npm -v // eg. 5.6.0

Test does it work without sudo:
$ npm install -g npm
$ npm -v // eg. 5.8.0

@w4-hojin
Copy link

w4-hojin commented Jun 12, 2018

Now, node LST is @8.
Even if we use node LTS, we can use yarn also.

@edPratt
Copy link

edPratt commented Mar 12, 2019

Since --without is deprecated, this no longer works. this worked for me

@idelendik
Copy link

brew prune has been replaced. Call brew cleanup instead.
Homebrew version: 2.2.2.

@idelendik
Copy link

brew install node --without-npm returns invalid option: --without-npm

Options have been removed from formula last year. brew install node is the way to get node and you’ll get npm with that. If you don’t want npm you could maintain a separate version of the node formula for yourself.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment