Disciplines · Decisions (ADRs)

ADR-0073: Nx Release Owns Versioning and Publishing

ADR-0006 (2026-01-10) selected Changesets as the monorepo's versioning and release mechanism.

Accepted · 2026-07-18
4sections2 minread

On this page

Status: Accepted Date: 2026-07-18 Authors: Development Team Supersedes: ADR-0006 (Versioning and Release Strategy) Superseded by: N/A

Context and Problem Statement#

ADR-0006 (2026-01-10) selected Changesets as the monorepo's versioning and release mechanism. Its implementation plan was never executed: no .changeset/config.json was ever created, no changeset files were ever authored, and no CI workflow invokes the changesets CLI. Meanwhile the release pipeline that actually shipped — .github/workflows/release.yml — was built on nx release: pnpm nx release version <v> --git-commit --git-tag followed by pnpm nx release publish --tag latest, driven by the release block in nx.json (conventional commits, per-project changelogs, GitHub release creation).

The 2026-07-16 monorepo architecture audit (finding C-8) flagged the resulting ambiguity: two release mechanisms coexisted in package.json (the dead changeset/version-packages/release scripts plus the @changesets/cli devDependency) with no explicit decision on which owns releases.

Decision#

nx release owns versioning, changelogs, and publishing. The changesets scripts and the @changesets/cli devDependency are removed. ADR-0006 is superseded: its analysis remains a valid record, but its chosen option was never implemented and the de facto standard is the one wired into CI.

Rationale:

  1. Reality wins. release.yml has only ever released via nx release; changesets never progressed past a devDependency. Re-platforming the working pipeline onto the unimplemented choice would be churn without benefit.
  2. Conventional commits are already enforced (commitlint with the registry-generated scope enum), so nx release's commit-parsing changelog input is trustworthy here — the "explicit intent" advantage ADR-0006 credited to changesets is substantially covered by the commit convention.
  3. One less toolchain. Nx already orchestrates build/test/lint; keeping version/publish in the same tool removes a second config surface.

Release scope#

nx.json release.projects is ["libs/*", "apps/*"]. Because slash-containing globs match project roots, this deliberately reaches only the single-level packages (libs/contracts, libs/proto, libs/openapi, …) — the public interface surface — and none of the ~3,300 nested internal workspace packages. Widening this scope is a deliberate per-package publishing decision, not a config cleanup (audit C-8): adding a nested glob would put every internal package into the publish set.

Consequences#

  • package.json no longer carries changeset, version-packages, or release scripts; @changesets/cli is removed from devDependencies.
  • Releases are dispatched via release.yml (workflow_dispatch) which computes the version and runs nx release version/publish.
  • Any future desire for changeset-style explicit intent files should be re-proposed as a new ADR rather than resurrecting the dormant tooling.