Skip to main content

Releasing and dist-tags

Which Archibald version you get depends on the npm dist-tag you install from, and which dist-tag a release lands on depends on the branch it was cut from. This page is the contract between the two: what each tag means for a consuming project, and what the release pipeline guarantees about it.

What to install

pnpm add @archibald/cli # latest — the current stable
pnpm add @archibald/cli@next # the version to upgrade to next
pnpm add @archibald/cli@rc # the release candidate being stabilised
pnpm add @archibald/cli@latest-8 # the newest 8.x, still maintained
dist-tagPoints atUse it when
latestThe current stable releaseAlways, unless you have a reason not to. A plain pnpm add @archibald/* resolves this.
nextThe newest version worth upgrading to — the release candidate of the upcoming line, or the current stable once it shipsYou want to try the next line early, ahead of the stable release.
alpha / beta / rcThe newest prerelease on that channelYou are testing a specific channel. rc is stabilising for release; alpha/beta are previews.
latest-<N>The newest release of major N, once N is no longer the mainline majorYou stay on an older major that still gets maintenance patches (e.g. latest-8).
snapshotA throwaway build of a single commitNever in a project you ship. Snapshots exist to try an unreleased fix; pin the exact version.
anything elseWhatever it was pointed at by handOnly when the team that published it told you to.

next never points backwards: it is only moved to a version newer than latest, so installing from it cannot downgrade you. See codemods for the migrations a major upgrade runs on the way.

note

A prerelease is not covered by the caret range a normal install writes — ^10.0.0 excludes 10.0.0-rc.1 by the semver rules. Installing from rc, beta or snapshot therefore pins the exact version, and stays pinned until you upgrade again.

Where releases come from

The branch decides the release kind and the dist-tag. Running the release pipeline with kind: auto (the default) resolves it as follows:

BranchKinddist-tagMoves next
masterstablelatestyes — a stable supersedes every prerelease of its line
release/<N>.<M>[.<P>]prereleasercyes — this is the line being stabilised
support/<N>.<M>.xmaintenancelatest-<N>no
developsnapshotsnapshotno
anything elsesnapshotsnapshotno

Prereleases off develop are possible, they are just never the default: set kind: prerelease and channel: alpha|beta explicitly. Those are previews of work in progress and consumers opt into them through the channel tag, so they never move next.

The pipeline form narrows itself as you fill it in, so an input that cannot be honoured is not offered: channel lists the channels only while kind is prerelease or still auto, publishOnly is fixed for a snapshot (which writes no git state to recover), and the runTests levels appear only on a lean publish run.

The three overrides — an explicit version, an explicit tag and forceTagPolicy — sit behind an advanced checkbox and stay fixed at their default until it is ticked. A normal release derives all three. Once ticked, tag is free text rather than a list: publishing under a name of your own is the point of it, and the reserved names are policed when the release runs rather than by the form, which cannot see the branch.

Only a tracked release (stable, prerelease, maintenance) writes anything to git: it commits the version bump and changelog, tags the commit v<version> and pushes both. Snapshots write no commit and no tag — they rewrite the manifests in place, publish, and restore the working tree — which is why a snapshot version carries the commit it was built from (9.1.0-snapshot.a1b2c3d).

Every branch bumps from the version in its own manifests (nx's currentVersionResolver: disk), so develop and a release/* branch can run in parallel without fighting over version numbers. After a release branch is cut, the first prerelease from develop for the following line needs an explicit bump: minor (or major) to open it.

The reserved-tag guard

latest, latest-<N>, next, alpha, beta, rc and snapshot are reserved: consumers resolve them automatically, so a mis-triggered pipeline pointing one of them at the wrong version is a bug in everyone's install. They are checked before every publish and every retag, however the tag was chosen — derived from the branch or typed into the pipeline's tag input:

  • latest may only be published from master.
  • next must be newer than latest, and comes from a release branch or from a stable release on master.
  • latest-<N> must point at an N.x version, and N must be older than the major latest currently serves.
  • alpha, beta and rc must point at a prerelease carrying that identifier — the rc tag cannot be pointed at a beta build. Publishing a channel from an unusual branch warns but is allowed.

Every other tag name is free-form and unchecked. That is the supported way to hand out a build under a name of your own:

pnpm run publish -- --kind=snapshot --tag=demo --dryRun=false

When a reserved tag genuinely has to be moved against the rules — repairing a tag that was left pointing at the wrong version, for instance — pass forceTagPolicy (the pipeline input, or --forceTagPolicy locally). Refusals then become warnings; nothing else changes.

Repairing a tag

pnpm retag moves one dist-tag to one version across every published package:

pnpm retag --version 9.1.0-rc.3 --tag next

It applies the same policy as a publish, and reports per package: if the registry drops some of the requests, the failures are listed and the command exits non-zero, so re-running it finishes the job rather than starting from an unknown state.