There is a feature in npm that affects every npm install
, every npm publish
, yet most npm users seem to be unaware of.
Time to talk about npm tags!
What they are
Let's jump right into it:
On every
npm install <package>
without an explicit version, a tag is used to resolve the right version number: Thelatest
tag.On every
npm publish
a tag is either updated or created. Yes, it defaults to thelatest
tag, too.
So let's assume a busy work day has just begun and you add a new package to your dependencies:
$ npm install cowsay
Now as you did not specify any version to install, how does npm decide which version to use? It uses the latest
tag!
Check this out:
$ npm show cowsay
cowsay@1.4.0 | MIT | deps: 4 | versions: 19
cowsay is a configurable talking cow
https://github.com/piuccio/cowsay
keywords: cow, cowsay, cowthink, figlet, talking, ASCII
bin: cowsay, cowthink
(...)
dist-tags:
latest: 1.4.0
published a month ago by piuccio <piuccio@gmail.com>
Have a look at dist-tags
. It shows only one tag, the latest
tag. Judging by npm show
's output we can already imagine what a tag's function is:
Tags are a mapping from some human-friendly identifier to a specific version number.
Aha! So when you do your casual npm install cowsay
, npm will fetch the package metadata (try npm show cowsay --json
), including a list of all published tags of the package. The latest
tag will tell npm what version to install.
So why doesn't npm just install the version with the most recent publishing timestamp? We will get to this in no time, but let's add a spoiler here:
Because the most recent npm publish
might not have published a stable version, but maybe some early beta version that the user is not supposed to run in production.
Using tags
Consuming
To install a package, but not the latest
tag:
$ npm install <package>@<tag>
A popular example would be:
# Install the latest alpha version of React
$ npm install react@next
Publishing
To publish a version of your precious package that should not be installed by default:
$ npm publish --tag <tag>
This way you can easily share some unstable code with others, so they can test it:
$ npm publish --tag beta
or
$ npm publish --tag testing-feature-new-dashboard
As already mentioned before, running npm publish
without a --tag
parameter will also update a tag: The latest
tag which is the default tag for publishing and installing.
Changing tags
You can always change tags to point to another version if you need to. Use the npm dist-tag
sub-command for that:
$ npm dist-tag --help
npm dist-tag add <pkg>@<version> [<tag>]
npm dist-tag rm <pkg> <tag>
npm dist-tag ls [<pkg>]
alias: dist-tags
Use it to fix the tag if you accidentally published a version using the wrong tag.
Difference to git tags
It's important to note that npm tags are semantically different to how git tags are commonly used, even though technically they are very similar.
A git tag points to a commit, which is the code at a particular point in time, and usually never changes. The git tag is essentially the equivalent of an npm version.
An npm tag on the other hand is a mutable pointer to a version, which in turn is an immutable pointer to the code at one particular point in time. So an npm tag is basically a meta pointer.
When thinking in git terms, both npm tags and npm versions could be implemented using git tags, just that the former type of tag would be considered mutable, while the version git tags would be considered immutable.
Profit $$
So how can we use that feature to our benefit in day-to-day work?
We can:
-
Share an unstable version with beta testers:
npm publish --tag beta
-
Publish a use-once-and-forget version:
npm publish --tag testing-new-feature
Installing that version on the other end will be just as simple:
$ npm install my-fancy-package@testing-new-feature
Release early, release often. Don't screw with your production users, though. Use npm tags.
Happy hacking!
Teaser photo by Paul Murphy on Unsplash. Shows spray tags, not npm tags.
Top comments (10)
Hi Andy,
Thanks for this article! This has helped me start to work on a new version of a module and share it easier with my colleagues in the other modules that require it. This was really clear and easy to read and understand.
Thanks for the great feedback, Phil! That's very nice to hear :)
Btw, I remember you from Berlin.js JSConf Special 2017. Any good meetups or conferences in Berlin coming up that you would recommend?
Ooh wow, that was a little while back! 😅
I'm not around Europe myself right now, so my finger is not exactly on that pulse right now. I'd always recommend Berlin.js for meetups. If you're into Angular, then the NG DE conference is coming up in August. And, outside of Berlin but still highly recommended, Ruhr JS is happening in October.
npm versions are analogous to git tags
npm tags are analogous to git branches
Hey Kevin!
Git branches are a history of commits (= changes), but AFAIK no history is tracked anywhere for npm tags. The npm tag is only a stateless pointer without any history. Like a git tag ;)
Haha yes I could have been more clear. I was just trying to be succinct on the train ride home. My point was that similar to git branches, npm tags are dynamic and moveable (latest and next will point to different versions as time varies, just like master would for git), whereas npm versions are fixed and unchanging, similar to how you would use git tags (e.g. v1.0.0).
Concise and easy to understand! I was facing a problem where I was burning through versions but had to publish before officially releasing. Using tags with timestamps in them made it possible to create unstable snapshots for testing. Thanks!
Thanks
nice article. help well.
Thanks for this Article! Was super useful!