Don’t Use `sudo` with `npm` …still
This is a rehash of an article I wrote in 2015 about how you shouldn’t use the
sudo command with npm. That is to say, you should never do
sudo npm … anything. I feel that this needs a bit of a rehash since I’ve learned some new techniques for managing Node.js and global modules on my development machine. The advice here also applies universally, but the specific examples are tailored to local development on OS X. Most of the examples should work on any popular OS with minor modifications.
Development machines, production machines, or machines from any environment shouldn’t be using
sudo npm or
sudo yarn (and probably shouldn’t be using
sudo at all, but that’s another story).
sudo npm install (and
sudo npm $ANYTHING) is still a bad idea ™ for the at least following reasons:
npm installand others have the ability to run arbitrary scripts. Due to how
npmis set up and the fact that you can alter the registry and it can use DNS, it is possible that you will accidentally install a malicious package in general, install a malicious package masquerading as a perfectly valid package, or install a package with good intentions that may run scripts that are somehow detrimental to your system if run as root.
sudo npm install(without
-g) will create a local directory that can only be altered by the root user. This can really screw things up for you if you try to do
npm <something>in the same directory or project later on.
sudo npm install -gwith a valid installation target can mess things up for you and make it hard to use
sudounder some circumstances in the future -- particularly if you change your
npmconfiguration midstream. The
rootuser can and will create files in your npm cache and potentially a file like
~/.npm/_locks, and future
npm install -gwill give you the dreaded
This remains true even with new security measures added to
npm. When it comes to using
npm, Just don’t do it!
Avoid Global Installs
I’ve found it favorable to avoid global installations altogether in favor of project-level installations. This is made even more convenient with the addition of
npx which will run a node module from the registry without permanently installing it to your system. So instead of running
npm install -g react-native && react-native init you can do
npx react-native init.
This will create a project that will have
node_modules/.bin/react-native, so as long as you’re in said project you can use
npx react-native or
yarn react-native to actually run the locally-installed
react-native command without having it installed globally. This also applies to tools like
grunt and pretty much any other such tool you can think of.
Note: for whatever reason, Ionic and Cordova only seem to work properly as global installs for now.
If you were to run
react-native init a lot, it would get annoying to have to install it with
npx every single time you needed it. In this case, installing a global module makes sense. Let’s look at how to do that without
Set npm’s Prefix
npm has a configuration called
prefix. This configuration setting tells
npm where to install global modules (
yarn also uses it). For more information on this configuration setting and others, see
npm help 7 config.
You can set this per-install using
npm --prefix=$PREFIX, but most likely you will want all of your global modules installed to the same place each time. You can update your global node configuration to do this. I did mine using
npm config set prefix ~/.npm. This is equivalent to editing your
~/.npmrc to include the line
prefix=~/.npm. You can make the prefix whatever you like, but it should be in a directory that your user has permissions to write to. That should be anything under your home directory,
But wait! You also have to include modules installed here to your
PATH. In your
.profile, or equivalent you should also set something like
export PATH="$HOME/.npm/bin:$PATH". This will allow you to run globally installed modules that are located in
You can also configure yarn to use its own prefix if you like, but for me I have to swap between using
npm for quite a few projects. It’s nice to have one configuration to worry about.
Using `n` to Manage Node.js Versions
My previous version of the article included instructions for using
nvm. It’s a great tool, and you should use it if you wish, but I prefer TJ Holowaychuk’s
n library for this purpose now.
Once you have installed a system-wide version of node, e.g. with
brew install node, you should have access to
yarn. Now you can set your prefix and
PATH. Once that’s done, you can run
yarn global add n or equivalent. You should now have access to the
which n should confirm this.
Now you’ll also have to update your
n tries to install the versions it manages to
/usr/local by default. I think that Homebrew suggests running
sudo chown -R $(whoami) $(brew --prefix)/* or something like that, but I’m not a huge fan of doing this. I’d rather manage things in my home directory.
You can add
export N_PREFIX=$HOME/.n or whatever you like. You must also add this to your path, for example:
export PATH="$PATH:$N_PREFIX/bin". Now you can use
n latest to install the latest version of node.js to a directory that you control.
To summarize, you can use the following steps to update your local OS X machine to allow you to use global Node.js modules and different versions of node without using
brew install node, or
apt-get install nodeor whatever you need to do to get node up on your machine. This should include executables
- Set your prefix for global installs, e.g.
npm config set prefix ~/.npm
- Update your PATH to include
~/.npm/bin. For example:
echo 'export PATH="$HOME/.npm/bin:$PATH"' >> ~/.zshrcif you’re using zsh.
At this point you’re good to go for installing global modules. I think it’s good to avoid installing global modules except for commands that you will use frequently that won’t be installed to a corresponding project. For one-off commands such as initiating projects that you will only do every once in a while, you can use
- Next, use
yarn global add nwhich should create
- Do the equivalent of
echo 'export N_PREFIX="$HOME/.n"' >> ~/.zshrcfor your shell configuration
Now you can run
n to install different versions of node to a directory that you control.
On build / production environments you should avoid global installs of modules as they are generally not needed. If they’re required, you can still do a similar setup with a user who only has permissions to install global node modules to a particular directory using
--prefix and so on.
Original Article (includes more information on working with other kinds of environments and using