npm dist-tags let you publish multiple versions of a package under different "channels" so users can opt into specific release streams.

Here’s a package named my-awesome-package with versions 1.0.0, 1.1.0, and 2.0.0-beta.1.

# Publish version 1.0.0 as the stable release
npm publish --tag latest

# Publish version 1.1.0, also as the stable release
npm publish --tag latest

# Publish version 2.0.0-beta.1 as a beta release
npm publish --tag beta

# Publish version 2.0.0-beta.2 as a newer beta release
npm publish --tag beta

Now, when someone installs my-awesome-package:

npm install my-awesome-package

By default, npm installs the version tagged latest. This would install 1.1.0 in our example.

To install the beta version, they’d explicitly specify the tag:

npm install my-awesome-package@beta

This would install 2.0.0-beta.2, the most recently published version with the beta tag.

You can view all available tags for a package:

npm view my-awesome-package dist-tags

Output:

{
  latest: '1.1.0',
  beta: '2.0.0-beta.2'
}

This system allows you to maintain distinct release channels. latest is for stable, production-ready code. next is often used for upcoming stable releases, giving users a preview before they hit latest. beta or alpha are for early testing of features and bug fixes. You can create any tag name you need, like canary, release-candidate, or feature-x.

The core problem this solves is managing the lifecycle of a package and providing different levels of stability and feature sets to consumers without forcing everyone onto bleeding-edge or outdated code. It decouples the concept of a package version number (which follows semantic versioning) from its discoverability and default installation.

Internally, npm treats dist-tags as metadata associated with a package on the registry. When you run npm publish --tag <tagname>, npm associates the currently published version with that tag name for that package. When you run npm install <packagename>@<tagname>, npm queries the registry for the package, retrieves its dist-tags, finds the version associated with the requested tag, and then installs that specific version. If no tag is specified, it defaults to latest.

Think of tags as symbolic links or pointers. The actual version numbers (1.0.0, 1.1.0, 2.0.0-beta.1) are immutable once published. The dist-tags are mutable pointers that can be moved to point to different versions. You can even move a tag backward to an older version if necessary, though this is less common for latest.

To change which version a tag points to, you simply publish a new version with that tag, or explicitly use npm dist-tag add to reassign it. For example, if you wanted to make 1.0.0 the beta release instead of 2.0.0-beta.2:

npm dist-tag add my-awesome-package@1.0.0 beta

This command removes the beta tag from 2.0.0-beta.2 and assigns it to 1.0.0. The npm view command would then reflect this change.

A common pattern is to use latest for stable releases, next for the version that will become the next latest, and beta or alpha for experimental builds. When a next version is deemed stable, you’d promote it:

  1. Publish the new stable version (e.g., 2.0.0) with the next tag. npm publish --tag next
  2. Wait for testing and feedback on the next channel.
  3. Once ready, reassign the latest tag to this new version. npm dist-tag add my-awesome-package@2.0.0 latest
  4. Optionally, remove the latest tag from the old stable version (e.g., 1.1.0) if you want to ensure latest strictly points to the newest stable. npm dist-tag rm my-awesome-package@1.1.0 latest (This is often not needed if you are just adding the new version to latest and are happy for latest to point to the most recently latest tagged version).

The most surprising thing about dist-tags is that they are not tied to semantic versioning rules. You can assign the latest tag to a version that is semantically older than another version on a different tag (e.g., latest: 1.5.0, beta: 2.0.0-beta.1). This is why npm install <package> without a tag always defaults to latest and doesn’t try to figure out what "most stable" or "highest version" means across all tags.

The next concept you’ll likely encounter is managing the deprecation of specific versions or tags within npm.

Want structured learning?

Take the full Npm course →