Releasing
One tag ships the packages and the image together. nx release versions the packages nx.json lists under release.projects as a set, because their relationship there is declared fixed, and image.yml builds the daemon image from the same commit. Both workflows wait for a tag matching v*, or for a run you start by hand from the Actions tab. A push to main reaches neither.
Turning releases on
Section titled “Turning releases on”publish.yml and image.yml read the RELEASE_DRY_RUN repository variable, and until it holds the exact string false a tag ships no artefact. But every other step still runs. pnpm verify runs on the tagged commit, nx release publish runs with --dry-run, and the image job builds both architectures and pushes neither. An unset variable reads as an empty string, and an empty string is not false, so a repository you have not configured stays in rehearsal. Turn releases on under Settings → Secrets and variables → Actions → Variables:
RELEASE_DRY_RUN = falseOnce set, it stays set. Clearing it puts the next tag back into rehearsal, and so does giving it any other value. Treat that as the recovery move if a release ever has to be stopped between tags.
Cutting a release
Section titled “Cutting a release”Version and tag on your own machine, so you can read the commit and the tag before either leaves it. --skip-publish stops nx after versioning and changelog generation, and what it leaves behind is a commit and a v tag in the local repository. Add --first-release to the very first release you cut, because the changelog has no earlier tag to compare against:
pnpm nx release --skip-publish --dry-run # read what it would dopnpm nx release --skip-publish # version, changelog, commit, taggit push --follow-tags--follow-tags is the half that starts the release. Pushing the commit alone leaves the tag behind and triggers neither workflow, and nx release publish then does the publishing inside the Publish job, where the credentials live. nx publishes the version each manifest carries, not the version the tag names, and a tag typed by hand can disagree with them. So the publish job compares the two before anything else happens, and a mismatch fails the run naming the manifest and both versions.
Two failures behave differently, and the difference decides what you do next. A failure inside pnpm verify stops the run before the publish step, so the registry never hears about it and you can retag the fix. But a run that breaks partway through publishing has already shipped whatever went out before it stopped, and npm does not let a published version be replaced. Recover from that one with a new version.
Rehearsing without shipping
Section titled “Rehearsing without shipping”Start either workflow from the Actions tab against any ref. Publish takes a dryRun checkbox, ticked by default; Image takes a push checkbox, unticked by default. Run with those defaults and the whole path executes while both registries stay untouched. Do it after every change to either file. A release is the one path with no other rehearsal.
Credentials
Section titled “Credentials”NPM_TOKEN lives on the npm environment and not on the repository, so the publish job is the only job here that can read it. It is a granular npm token with read and write access to the scope the packages publish under. The image needs no secret of its own. It signs in to the registry with the run’s own GITHUB_TOKEN, under the packages: write scope the workflow requests.
Provenance and attestation
Section titled “Provenance and attestation”npm builds a provenance statement only for a package whose repository field names a public repository. While this repository is private the publish job switches provenance off, and the image job skips its attestation on the same condition. Both come back by themselves the day the repository opens. Neither needs a workflow edit.
Documentation deploys on its own
Section titled “Documentation deploys on its own”pages.yml deploys the site on a push to main touching the book or the app that builds it, and a tag does not reach it. So a documentation fix reaches readers without a release, and a release never waits for the site.