Run NPM executables without installing globally

Have you ever seen this in the documentation for some package you plan to use for your Node.js project because of some executable it provides?

Installation

$ npm install -g <some-node-package>

Why this is a problem?

When I see this, I think "But I just want to use it for this one thing! Why do I need to install it globally?!"

Problems can arise from having to install dependencies this way when we have projects that require different versions of the same dependency on the same machine, when we switch between versions of Node and our installed packages disappear, etc. Ideally, we should be able to run the executable node modules without having to add that -g when installing them.

How do I fix it?

There's an easy solution. All you need to do is add one line to your .bash_profile file (or wherever $PATH is defined in your environment) so we can run executable files in the working directory's node_modules:

export PATH=./node_modules/.bin:$PATH

The . at the beginning refers to the current working directory. If you cd to a place that has a node_modules directory in it, your terminal will look there for executables because NPM puts all of the executables for locally installed packages inside node_modules/.bin.

Let's try it!

Let's install a commonly used NPM package that has an executable. In this case we will use node-static.

First, make a directory for our temporary project.

$ mkdir /tmp/test-project
$ cd /tmp/test-project
$ npm install node-static
$ ls node_modules/
node-static
$ ls node_modules/.bin
static

At this point, we should have everything we need in our directory. Let's check if our PATH is set up correctly.

$ which static
./node_modules/.bin/static

Running which static should tell us that the executable is in our current working directory's node_modules. If not, check that the output of running echo $PATH contains ./node_modules/.bin/ somewhere. Let's see if it works by creating a file to serve and checking if we can see it in our browser.

$ echo "Hello world" > index.html
$ static
serving "." at http://127.0.0.1:8080

When we look at it in our browser, we should see something like this:

Now, when we create a project that uses static or some other executable installed via NPM, we can use it without installing it globally!

Caveats

One issue with this is that it will only work when you are in the root directory of the project. If your working directory is a subdirectory of the project (e.g. /lib, /src, etc.), you won't be able to run the executables in node_modules/.bin anymore. There are some workarounds for this, but they aren't perfect. Make sure your working directory is the top of your project when you try to run an executable.

If you're working in a team, this will add an extra step for getting your colleagues' environments set up. If you decide to use this and one of your teammates says "I installed everything but it says command not found!" it may be because his/her PATH isn't set up correctly.


If you found this useful or want to ask me anything about it, feel free follow me on Twitter!