What is npm?

Recently I wrote about Node.js’s two module systems, the traditional CommonJS module system, and the newer ECMAScript module system. These module systems are related to, but distinct from, package systems. A module is a thing loaded and executed at runtime. A package is a thing downloaded at “install time”. Packages can provide modules. There is only one one package system for Node.js that’s worth mentioning: NPM. Let’s take a look.

The NPM docs have an excellent, succinct definition of a “package”:

Note that this definition does not mention “Node.js modules”. An NPM package can contain arbitrary stuff. For example, you can distribute CSS via NPM. Just throw it anywhere in the folder. The contents are limited only by the vague NPM terms of use.

Yes, you can npm install foo/bar/baz/, a directory that contains a package.json. The package.json just has to have name and version fields. This adds "packagename": "file:foo/bar/baz" to your dependencies, and creates node_modules/packagename as a symlink to it.

Yes, you can npm install tarball.tar.gz, a gzipped tarball containing a package.json. This adds "packagename": "file:tarball.tar.gz" to your dependencies, and unzips the gzipped tarball into node_modules/packagename.

Yes, you can npm install http://example.com/tarball.tar.gz. This adds "packagename": "http://example.com/tarball.tar.gz" to your dependencies, and unzips the gzipped tarball into node_modules/packagename.

Yes, you can npm install 'git://github.com/jameshfisher/lodash.git#jims-fork'. This adds "lodash": "git://github.com/jameshfisher/lodash.git#jims-fork" to your dependencies, checks out the specified commit, and copies it into node_modules/lodash. This could come in handy for maintaining your own fork of a package.

Onto more familiar territory. When we run npm install lodash@4.17.20, the 4.17.20 is a “version”. This identifier maps to the URL https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz, a raw URLs to a tarball hosted on the NPM registry. However, NPM adds "lodash": "^4.17.20" to your dependencies, rather than adding the raw URL. You can query the NPM API to get the URL with:

$ curl -s https://registry.npmjs.org/lodash | jq '.versions | .["4.17.20"].dist.tarball'
"https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz"

NPM has a separate thing called “tags” which uses the same syntax as versions. For example, npm install jquery@beta installs the beta tag. Currently, the beta tag maps to version 3.5.1. NPM puts "jquery": "^3.5.1" in your dependencies, so the fact that you installed a tag is lost. You can see the current tag-to-version mapping with:

$ curl -s https://registry.npmjs.org/jquery | jq '.["dist-tags"].beta'
"3.5.1"

When you run npm install jquery, this is equivalent to npm install jquery@latest. It puts "jquery": "^3.5.1" in your dependencies, and forgets that you just installed latest.

Next time, I’ll look at making an example package, publishing it, and showing it in use.

Tagged #programming, #javascript.
👋 I'm Jim, a full-stack product engineer. Want to build an amazing product and a profitable business? Read more about me or Get in touch!

More by Jim

This page copyright James Fisher 2020. Content is not associated with my employer. Found an error? Edit this page.