Do you really need global NPM packages?

Use NPM and “package.json” at their full power

To better understand the meaning of this post let’s start with what the package.json is and what it means to your project.

From :

The best way to manage locally installed npm packages is to create a package.json file.
A package.json file affords you a lot of great things:
1. It serves as documentation for what packages your project depends on
2. It allows you to specify the versions of a package that your project can use using semantic versioning rules
3. Makes your build reproducable which means that its way easier to share with other developers.

Let’s focus on the last sentence:

Makes your build reproducable which means that its way easier to share with other developers.

In an utopic world this means that if you download a repo from GitHub and you just run “npm install” you should be able to be productive as-soon-that-it-ends-downloading-packages.

That’s a huge statement since every project you’ll find on GitHub requires you to install some global packages, usually Gulp or Grunt (take a look at FreeCodeCamp readme for a reference), so basically 99% of the time you’ll not be ready to work with just a simple plain “npm install”.

Let me explain better

Take as example a project that requires Gulp as a dependency.

Even the Gulp ‘Getting started’ page suggests you to install it 2 times!

They usually suggest you to install it globally in order to have the “gulp” command available on the entire system berfore being able to work on the project (notice that when you perform “npm install” it will download another copy of the package in the project’s node_modules folder if it’s written in the package.json file).

Let me be clear: installing a global package -if it’s just one step more- isn’t such a pain. But this isn’t the only reason about why I’m criticizing this requirement.

So you need to download it at least 2 times, and you know if you need to install it globally only if the mantainer has written it. Since developers are known to be lazy, or the developer didn’t intended his project to be developed from others than him, you may find yourself head banging while trying to figure it out what package is missing.

Force yourself to save the packages your project needs in the package.json file.
Think about your project like it’s in a sandbox environment, no access to external resources is allowed.

Updating global packages can break your other projects

Updating global packages can break your other projects that likely were depending on a certain version of a package. It shouldn’t happen, but if it happens… well this will cause to you some more headaches when you come back working on your other projects and they simply just aren’t working anymore. I can bet you don’t want it.

When all of your projects suddenly stop working

But I need global packages like Gulp, Grunt or Webpack and many more in order to run tasks and other fancy things!

NPM and the “package.json” file are here to rescue you

package.json scripts example

In the package.json file you can write custom scripts that you can launch from your shell with “npm run” plus the script name (eg. “npm run development” will launch the local webpack-dev-server) and it goes searching for the package in your project local node_modules folder; you don’t need to have it installed globally nor you don’t need to know -nor to write- the path where the package is installed.

You can also pass argument to scripts:

npm run gulp -- sass

That’s a huge time saver even for open source mantainers and contributors. The mantainer can just provide the same list of NPM commands without needing the contributor to learn new commands if the maintainer changes the project build system (eg. he switches from Grunt to Gulp or to Webpack) or he changes his project test framework.

In your development flow using npm scripts instead of global installed packages doesn’t change nothing: you can keep writing your “gulpfile.js” or your “webpack.config.js” as you were doing before, and they will still work as they were doing before.

Let’s recap


  1. You have to write a bridge for every package that may wanted global installation


  1. Maintainability
  2. No more global package conflicts and broken projects
  3. No more missing-package headache
  4. You have a little wiki of the useful commands immediately available
  5. When someone clones your project all they are required to do is run “npm install” and they will actually get all of the dependencies installed, and they are ready to work on it

So, for me, having only local packages is an easy win over having to install global packages, updating them while risking to break other projects and having to use ‘sudo’ if I haven’t installed Node with Homebrew. And if you are on OS X El Capitan you may encounter some troubles using ‘sudo’ with his SIP.

If your project needs ‘sudo’ to start, then you are doing it really wrong.

Note that not every global package will cause all these not-so-fancy things, and sometimes you are just forced to do that(eg. linting code). This is just a “be careful on what you are doing” advice, not an “absolutely stay away from global packages” 😉.

Like what you read? Give Jonathan a round of applause.

From a quick cheer to a standing ovation, clap to show how much you enjoyed this story.