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-tag | Points at | Use it when |
|---|---|---|
latest | The current stable release | Always, unless you have a reason not to. A plain pnpm add @archibald/* resolves this. |
next | The newest version worth upgrading to — the release candidate of the upcoming line, or the current stable once it ships | You want to try the next line early, ahead of the stable release. |
alpha / beta / rc | The newest prerelease on that channel | You 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 major | You stay on an older major that still gets maintenance patches (e.g. latest-8). |
snapshot | A throwaway build of a single commit | Never in a project you ship. Snapshots exist to try an unreleased fix; pin the exact version. |
| anything else | Whatever it was pointed at by hand | Only 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.
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:
| Branch | Kind | dist-tag | Moves next |
|---|---|---|---|
master | stable | latest | yes — a stable supersedes every prerelease of its line |
release/<N>.<M>[.<P>] | prerelease | rc | yes — this is the line being stabilised |
support/<N>.<M>.x | maintenance | latest-<N> | no |
develop | snapshot | snapshot | no |
| anything else | snapshot | snapshot | no |
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:
latestmay only be published frommaster.nextmust be newer thanlatest, and comes from a release branch or from a stable release onmaster.latest-<N>must point at anN.xversion, andNmust be older than the majorlatestcurrently serves.alpha,betaandrcmust point at a prerelease carrying that identifier — therctag 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.