DEV Community πŸ‘©β€πŸ’»πŸ‘¨β€πŸ’»

DEV Community πŸ‘©β€πŸ’»πŸ‘¨β€πŸ’» is a community of 963,274 amazing developers

We're a place where coders share, stay up-to-date and grow their careers.

Create account Log in
Cover image for When to Use Global NPM Installs? Rarely
Tally Barak
Tally Barak

Posted on • Updated on

When to Use Global NPM Installs? Rarely

Run npm bin

It is widespread to go on a quick start page of some tool and utility and find instructions similar to this one:

npm install - global cool-package
cool start
Enter fullscreen mode Exit fullscreen mode

This command is likely to work, but theβ€Š--global should make your eyebrow rise. It is barely needed or recommended to install packages globally.

Well, WhyΒ Not?

There are a few reasons for you to avoid installing packages globally:

But it works forΒ me…

Who of us, developers, have never heard this? Your colleague is trying to run something you just told them to, and… fails. But it works for me, you tell them.
Global packages can be it. If you have some package they do not have, or if there is a version mismatch between your machines, that might be a problem here.

CI isΒ failing

That problem is similar to the machine mismatch described above. You are setting a CI that is trying to run a command, but it cannot find it. The reason is that the command was part of a package installed locally on your machine.

That version does notΒ work

One of the worst problems when relying on global packages is version compatibility. If you are working on multiple projects, you are likely to have different versions of packages. Version 3 for project A and version 4 for project B. Sadly, only a single version can be installed globally. You need to work this out.

Oh, a new nodeΒ version!

Are you using nvm to manage your node versions? (and if you do notβ€Š-β€Šhave a look at it. It is awesome!). If you switch to a new version of a node, even a minor change, your global packages are gone. If you are a very careful maintainer, you will be using the option --reinstall-packages-from=default. But if you are like me, you will find sometime later that a specific command does not work, and realize you did not migrate your packages.
Minimizing the number of packages can surely save some precious time.

OK, I am convinced. I will try to avoid using global packages. What is the recommended way to work?

Keep ThemΒ Local

In most cases, you should keep your packages local to your projects. Save all the packages needed for a project locally with the compatible version or versions range.

npm install --save cool-package
or
yarn add cool-package
Enter fullscreen mode Exit fullscreen mode

But this raises an issue: when you install a package globally, you can easily run it by typing its executable name:

cool start
Enter fullscreen mode Exit fullscreen mode

If you try to do that in a local package, you will get an error that the command was not found. NPM installs the executable under the node_modules/.bin folder. When running a command, the shell does not search on this path. The NPM global path, on the other hand, is added to the shell path (run echo $PATH to view it).
There are a few ways to solve this:

Run the command via npmΒ script.

Define the command in the npm script:

{
"name": "my-package",
"scripts": {
"build": "cool build",
"test": "cool test"
}
}
Enter fullscreen mode Exit fullscreen mode

Now you can run the command by running:

npm run build
Enter fullscreen mode Exit fullscreen mode

Pro Tip: If your command requires config arguments that start with double dashes, you need to specify it twice when running via npm script. So if you want to run cool build --watch You need to run: npm run build -- --watch (with two sets of dashes). Otherwise, the command will not be recognized.

Run with npmΒ bin

However, there are scripts that you want to run only occasionally, and it does not make sense to create a script for each one of them. In this case, you can run it directly by specifying:

node_modules/.bin/cool rare-command.
Enter fullscreen mode Exit fullscreen mode

A shorter and friendlier way to do it is to use the npm and yarn bin command that returns the path to the executable path, and you can run:

$(npm bin)/cool rare-command
Enter fullscreen mode Exit fullscreen mode

Have a command that you use often, but you do not want to put it in a script? set an alias for it, such as:

alias cl=$(npm bin)/cool
Enter fullscreen mode Exit fullscreen mode

This command runs the cool script that is local to the project you run it.

Use NPX for LocalΒ Scripts

Starting NPM 5.2, NPM has a new package called NPX. NPX is extremely powerful, and too often, its powers are overlooked.
Use NPX to run local scripts: By merely typing npx cool inside a folder where cool-package is installed, NPX finds the local installation and run the script. If you need to pass any arguments, just send them, without any changes.

Use NPX for uninstalled Packages

create Vue app usingΒ npx

When starting a new project using a CLI, such as Angular CLI, React Create App, or Vue CLI, the project does not yet exist. Therefore, you cannot install the generator package inside the project.

NPX is a lifesaver here, as you can run:

npx create-react-app my-app
Enter fullscreen mode Exit fullscreen mode

NPX downloads the package to a temp folder and executes the command from there.

In the create-react-app, the name of the script is the same as the name of the package. If the package name is different from the command, you can specify the package name to be installed.

npx -package @angular/cli ng new my-app
Enter fullscreen mode Exit fullscreen mode

Use Yarn

When installing Yarn, the bin command is automatically mapped to the yarn command, so you can run it as:

yarn cool
Enter fullscreen mode Exit fullscreen mode

(Credit to @bnaya for this excellent comment!)

When To Use A GlobalΒ Package?

After that said, there are cases where global packages are acceptable. The rule of thumb should be to use it when:

  • You run the commands mostly outside the context of specific projects.
  • You run the command relatively often, and you do not wait for NPX cache every time.
  • You are not extremely sensitive to the package's version, or versions do not change often.

For me, an example of such a package is http-serverΒ . I need it sometimes when I want to run a simple, well, HTTP server from a local folder for development and testing options. In this case, I would install the package globally.
Ah, and do not forget to update the version occasionally. Use npm outdated -g to see what packages need an update.

Conclusion

Run npm ls -g --depth=0 to see your currently installed global packages. Review them carefully, and always be conscious about the packages you install globally.

More often than not, you can avoid global packages and save yourself some precious debugging time.

Top comments (7)

Collapse
 
omrilotan profile image
Omri Lotan

Hi, Tally. Good read, I agree completely. Global installs are meant for CLI tools you use frequently with no relation to a specific node application.

One small correction tho (pro tip): when you run npm run build --watch the --watch flag applies to npm and not to the internal command. If you want to pass arguments in use the -- operator (getopt), which will pass all subsequent arguments onto your script npm run build -- --watch

Collapse
 
tallyb profile image
Tally Barak Author

You are absolutely right. This was the original intent, but lost in editing (I copied the article from a draft elsewhere). Thanks for the comment.

Collapse
 
tuwang profile image
TuWang

Oh no... what did I do all these time...

Collapse
 
opensas profile image
opensas

Nice article, just a small typo: npx -package @angular/cli ng new my-app should be npx --package @angular/cli ng new my-app or npx -p ... for short

Collapse
 
loujaybee profile image
Lou (πŸš€ Open Up The Cloud ☁️)

Very true, ever since it being able to reference the binary, I've been going through and cleaning these up in all the projects I come across. πŸ˜„

Collapse
 
loujaybee profile image
Lou (πŸš€ Open Up The Cloud ☁️)

Also, nice to see a fellow DX'er!

Collapse

In defense of the modern web

I expect I'll annoy everyone with this post: the anti-JavaScript crusaders, justly aghast at how much of the stuff we slather onto modern websites; the people arguing the web is a broken platform for interactive applications anyway and we should start over;

React users; the old guard with their artisanal JS and hand authored HTML; and Tom MacWright, someone I've admired from afar since I first became aware of his work on Mapbox many years ago. But I guess that's the price of having opinions.