Node.js package management system: Installing an npm package

1. Installing an npm package

The npm install command makes it easy to install packages upon finding one of your dreams, as follows:

$ npm install express



The named module is installed in node_modules in the current directory. During the installation process, the package is set up. This includes installing any packages it depends on and running the preinstall and postinstall scripts. Of course, installing the dependent packages also involves the same installation process of installing dependencies and executing pre-install and post-install scripts.

Some packages in the npm repository have a package scope prepended to the package name. The package name in such cases is presented as @scope-name/package-name, or, for example, @akashacms/plugins-footnotes. In such a package, the name field in package.json contains the full package name with its @scope.

We’ll discuss dependencies and scripts later. In the meantime, we notice that a version number was printed in the output, so let’s discuss package version numbers.

2. Installing a package by version number

Version number matching in npm is powerful and flexible. With it, we can target a specific release of a given package or any version number range. By default, npm installs the latest version of the named package, as we did in the previous section. Whether you take the default or specify a version number, npm will determine what to install.

The package version is declared in the package.json file, so let’s look at the relevant fields:

{ …

“version”: “1.2.1”, “dist-tags”: {

“latest”: “1.2.1”


… }

The version field obviously declares the current package version. The dist-tags field lists symbolic tags that the package maintainer can use to aid their users in selecting the correct version. This field is maintained by the npm dist-tag command.

The npm install command supports these variants:

$ npm install package-name@tag

$ npm install package-name@version

$ npm install package-name@version-range 

The last two are what they sound like. You can specify express@4.16.2 to target a precise version, or express@”>4.1.0 < 5.0″ to target a range of Express V4 versions. We might use that specific expression because Express 5.0 might include breaking changes.

The version match specifiers include the following choices:

Exact version match: 1.2.3

At least version N: >1.2.3

Up to version N: <1.2.3

Between two releases: >=1.2.3 <1.3.0

The @tag attribute is a symbolic name such as @latest, @stable, or @canary. The package owner assigns these symbolic names to specific version numbers and can reassign them as desired. The exception is @latest, which is updated whenever a new release of the package is published.

In selecting the correct package to use, sometimes we want to use packages that are not in the npm repository.

3. Installing packages from outside the npm repository

As awesome as the npm repository is, we don’t want to push everything we do through their service. This is especially true for internal development teams who cannot publish their code for all the world to see. Fortunately, Node.js packages can be installed from other locations. Details about this are in npm help package.json in the dependencies section. Some examples are as follows:

  • URL: You can specify any URL that downloads a tarball, that is, a .tar.gz file. For example, GitHub or GitLab repositories can easily export a tarball URL. Simply go to the Releases tab to find them.
  • Git URL: Similarly, any Git repository can be accessed with the right URL, for example:

$ npm install git+ssh://user@hostname:project.git#git-tag

  • GitHub shortcut: For GitHub repositories, you can list just the repository specifier, such as expressjs/express. A tag or a commit can be referenced using expressjs/express#tag-name.
  • GitLab, BitBucket, and GitHub URL shortcuts: In addition to the GitHub shortcut, npm supports a special URL format for specific Git services with URLs like github:user/repo, bitbucket:user/repo, and gitlab:user/repo.
  • Local filesystem: You can install from a local directory using a URL with the: file:../../path/to/dir.

Sometimes we need to install a package for use by several projects, without requiring that each project installs the package.

4. Global package installs

In some instances, you want to install a module globally, so that it can be used from any directory. For example, the Grunt or Babel build tools are widely useful, and conceivably you will find it useful if these tools are installed globally. Simply add the -g option:

$ npm install -g grunt-cli 

If you get an error, and you’re on a Unix-like system (Linux/Mac), you may need to run this with sudo:

$ sudo npm install -g grunt-cli 

This variant, of course, runs npm install with elevated permissions.

If a local package install lands in node_modules, where does a global package install land? On a Unix-like system, it lands in PREFIX/lib/node_modules, and on Windows, it lands in PREFIX/node_modules. In this case, PREFIX means the directory where Node.js is installed. You can inspect the location of the directory as follows:

$ npm config get prefix


The algorithm used by Node.js for the require function automatically searches the directory for packages if the package is not found elsewhere.

ES6 modules do not support global packages.

Many believe it is not a good idea to install packages globally, which we will look at next.

Avoiding global module installation

Some in the Node.js community now frown on installing packages globally. One rationale is that a software project is more reliable if all its dependencies are explicitly declared. If a build tool such as Grunt is required but is not explicitly declared in package.json, the users of the application would have to receive instructions to install Grunt, and they would have to follow those instructions.

Users being users, they might skip over the instructions, fail to install the dependency, and then complain the application doesn’t work. Surely, most of us have done that once or twice.

It’s recommended to avoid this potential problem by installing everything locally via one mechanism—the npm install command.

There are two strategies we use to avoid using globally installed Node.js packages. For the packages that install commands, we can configure the PATH variable, or use npx to run the command. In some cases, a package is used only during development and can be declared as such in package.json.

Source: Herron David (2020), Node.js Web Development: Server-side web development made easy with Node 14 using practical examples, Packt Publishing.

Leave a Reply

Your email address will not be published. Required fields are marked *