I'm writing this post since there were a lot of guides online on how to set up NPM so you can do npm install -g (that is, a global NPM install) on macOS or Linux without superuser privileges, but all those guides recommended a rather strange directory structure, such as a very strange looking ~/.npm directory loose in your home folder. This is a bad idea for a several reasons.

In this article I intend to show the very simple steps to set it to a much better location of ~/.local. This follows conventions and plays nice with many different applications, on both Linux-based systems, and macOS. 1

When npm tries to install to globally, it tries to install it's packages to the sensible location of /usr/local/. When you aren't a super user, this gives the warning checkPermissions Missing write access to /usr/local/lib and error Error: EACCES: permission denied, access '/usr/local/lib' and fails. Other package installers (such as Python's pip) already ship, at least on Ubuntu, with a concept of a user-specific local directory of ~/.local/ to replace the global /usr/local/ to avoid such warnings.

Thus, let's just reuse this existing convention.

Step 1: Configure NPM

npm config set prefix ~/.local  

Now NPM will install your global executables to ~/.local/bin, and the libraries to ~/.local/lib/node_modules/

Step 2: Add ~/.local/bin to your path

If you haven't already, open up the conf file of your favorite shell (such as ~/.bashrc for Bash), and add in:

PATH=~/.local/bin/:$PATH  

That's it. You're done.

Now, for why we are doing it this way instead of the incredibly common suggestions online of ~/.npm. The most obvious is convention: other applications use ~/.local also. However, ~/.npm is particularly a terrible choice. Whatever you do, DON'T USE ~/.npm/ as your user installation directory. Why is ~/.npm such a bad choice? ~/.npm is the default npm cache directory! Thus, if you clear the cache, you'd wipe your modules too. You can check to see what your cache directory is with npm config ls -l | grep cache.

Now can anyone tell me why this isn't the default, and why there's so much misinformation about this online?

  1. Relevant reading: PEP 370: it's about Python, but useful nonetheless