TS-11: Versioning

Software components that are released, distributed, or otherwise consumed by other parties — including libraries, web services, end-user applications, command-line tools, and infrastructure modules — SHOULD use a consistent versioning scheme for their releases. This makes it easier to manage compatibility between components and to communicate changes to consumers.

Choosing a versioning scheme

The two versioning schemes covered in this standard — semantic versioning (SemVer) and calendar versioning (CalVer) — are suited to different types of software:

  • SemVer is RECOMMENDED for software with a stable, contractual interface that consumers depend on: libraries, public APIs, and SDKs. The semantic increments (major, minor, patch) communicate compatibility precisely.
  • CalVer is RECOMMENDED for software where time-of-release is the most meaningful identifier and where backwards-compatibility commitments are softer: end-user applications, internal services, infrastructure modules, command-line tools, and continuously-deployed software (see TS-10: Releasing).

When SemVer would technically apply but the surface area of the "public API" is fuzzy or shifting (eg. end-user GUIs, where "breaking change" is hard to define), prefer CalVer.

A single version string SHOULD use one scheme consistently. However, the two schemes MAY be layered for different audiences within the same project — for example, SemVer for internal versioning (used by developers and dependency managers) and CalVer for public release identifiers (used in marketing and end-user communication). Where layered schemes are used, both identifiers MUST be unambiguously mapped to the same source-control tag and artifact, so the binding remains traceable.

Semantic versioning

It is RECOMMENDED to use the Semantic Versioning 2.0.0 scheme for versioning software components. This is a widely adopted standard.

Semantic version numbers follow this format:

v{major}.{minor}.{patch}
  • <major>: Increment this number by 1 when the release includes incompatible or breaking API changes. For user-facing GUIs, a breaking change could be considered to be a change in the behavior of an existing UI control, or removal of existing controls.
  • <minor>: Increment this number by 1 when the release includes user-facing changes that do not break backwards compatibility — new features, bug fixes, and runtime-quality improvements.
  • <patch>: Increment this number by 1 when the release includes only internal changes that do not affect the user-visible contract — refactors, formatting changes, maintenance, and chores.

The following is a representative chronology of semantic version number progressions:

  • v1.0.0
  • v1.1.0
  • v1.2.0
  • v1.2.1
  • v2.0.0
  • v2.0.1
  • v2.0.2
  • v2.1.0

Bumping versions from commit history

The mapping between SemVer increments and the commit conventions defined in TS-9: Version Control is as follows:

  • Commits flagged BREAKING trigger a major bump.
  • Commits of type feature, fix, or runtime (without BREAKING) trigger a minor bump. These are the user-facing changes that the version number communicates to consumers.
  • Commits of type refactor, format, maintenance, or chore (without BREAKING) trigger a patch bump. These are internal changes that affect the codebase but not the user-visible contract.
  • Commits flagged INCOMPAT (internal-only breaking changes) MUST NOT, on their own, trigger a major bump — they affect internal callers but not the public API contract, and so they bump patch like any other internal change.
  • Commits of type step, release, merge, and revert are version-neutral; they do not trigger bumps.

When a release accumulates multiple commits, the highest applicable bump wins: BREAKING beats feature/fix/runtime beats refactor/format/maintenance/chore.

Tools such as semantic-release and release-please can be configured to follow this mapping automatically. Manual version selection MUST follow the same rules.

Experimental features

Features that are clearly marked as "experimental", and that require users to explicitly opt-in to use them, MAY be subsequently changed, modified significantly, or removed in a breaking way without triggering a major version bump. The experimental status serves as an explicit contract that API stability is not guaranteed.

Experimental features MUST be documented as such, clearly visible to users who discover them, and their unstable status MUST be communicated in release notes.

Once an experimental feature becomes stable and is no longer marked as experimental, the usual SemVer rules apply – breaking changes to that feature then require a major version bump.

Calendar versioning

Semantic versioning is the RECOMMENDED default, but it is not the only viable scheme. Calendar versioning (CalVer) — where version strings encode dates rather than semantic increments — is well-suited to projects with regular release cadences and to software where backwards-compatibility commitments are not the central concern.

Common CalVer formats include YYYY.MM.DD, YYYY.MM, YY.0M.MICRO, and YYYY.MINOR.PATCH. Examples: 2025.07.14, 25.07, 2026.0.1. The choice of granularity depends on release frequency.

CalVer is often appropriate for:

  • Software with continuous deployment, where individual SemVer-style increments are too granular to be informative (see TS-10: Releasing).
  • Time-boxed releases where the date itself is the most meaningful identifier (eg. Ubuntu’s YY.MM releases).
  • Internal tools, infrastructure components, and operating-system-style projects without a consumer-facing API contract.

CalVer SHOULD NOT be combined with SemVer increments in the same string (eg. 1.2.3-2025.07), as this defeats the purpose of both schemes. A project SHOULD pick one and apply it consistently.

All other guidance in this standard — tagging conventions, the v prefix, build metadata, pre-release suffixes — applies equally to CalVer schemes.

Tagging

Each release MUST be marked in version control by an annotated Git tag whose name is the version string prefixed with v. For example, version 1.2.3 is tagged v1.2.3. The v prefix is part of the tag convention, not the version string itself — published version strings (in package metadata, release notes, etc.) MAY omit it.

Tags MUST be annotated (git tag -a), so they carry a tagger, timestamp, and message. Tags SHOULD be signed (git tag -s) where commit signing is in use; see TS-9: Version Control.

Tags MUST be permanent. Once pushed to the reference repository, a tag MUST NOT be deleted, moved, or recreated against a different commit. If a release is botched, cut a new release with a new version number rather than retagging.

The tag and the artifacts produced from it MUST share the same identifier — eg. if v1.2.3 is the tag in the source repository, v1.2.3 is also the identifier under which the corresponding compiled artifacts are stored in the artifact repository (see TS-9: Version Control).

Tag a release as soon as possible after the integration that completes it, ideally as part of the automated pipeline that promotes commits to the release trunk. Tags are the canonical record of versioned releases — merge commits indicate when changes were integrated, but only tags identify which version corresponds to a given commit.

Tip

For longer release notes, the -F option reads the tag message from a file: git tag -a v1.2.3 -F RELEASE_NOTES.md. To push commits and any annotated tags reachable from the pushed commits in a single operation, use git push --follow-tags.

Version zero

v0.x.x releases are NOT REQUIRED to comply with the Semantic Versioning rules.

Version zero releases SHOULD be used to preview, pre-release, or prototype builds of new software. These releases are considered to be unstable and not production-grade. Breaking changes MAY be introduced to version zero releases without bumping then major version number.

Pre-release versions

For pre-release versions, the semantic version number SHOULD be followed by a hyphen and then a stage identifier, followed by a dot and then a zero-indexed incrementing integer.

v{major}.{minor}.{patch}-{stage}.{inc}

Common stage identifiers include:

  • alpha — early, unstable, feature-incomplete builds.
  • beta — feature-complete but possibly buggy preview builds.
  • rc — release candidates expected to be stable and unlikely to change before final release.
  • canary — automated nightly or per-commit builds, used for early integration testing.
  • dev — single-revision builds used for testing through the registry.
  • next — sometimes used in place of beta or rc to identify the upcoming version.

The choice of identifier depends on the project’s release pipeline and ecosystem conventions.

Example of a release order, top-to-bottom

v1.0.0-alpha.0
v1.0.0-alpha.1
v1.0.0-alpha.2
v1.0.0-beta.0
v1.0.0-beta.1
v1.0.0
v1.1.0-alpha.0
v1.1.0-alpha.1
v1.1.0-beta.0
v1.1.0

This is an extension of the Semantic Versioning standard and is based on the convention used by the NPM registry of JavaScript packages. This convention may need to be adapted for other package managers and software ecosystems.

Distribution channel tags — such as latest, stable, next, or lts, assigned by package managers to point to specific versions — are a related but distinct concept. They are not part of the version string itself; they are metadata maintained externally by the registry. Consult your package manager’s documentation for how distribution channels are configured.

Build metadata

SemVer 2.0.0 supports an OPTIONAL build metadata suffix, separated from the version (or pre-release) by a +:

v{major}.{minor}.{patch}[-{prerelease}][+{build-metadata}]

Examples: v1.2.3+sha.5114f85, v1.0.0-rc.1+20251201.

Build metadata MUST NOT affect version precedence — 1.2.3+a and 1.2.3+b are considered the same version. It is intended for embedding non-version-determining build context: commit SHAs, build numbers, build dates, or CI run identifiers.

Build metadata is OPTIONAL but RECOMMENDED in contexts where the source-tag-to-artifact binding needs to be made explicit in the version string itself — such as continuous deployment pipelines where artifact identifiers are not separately tracked. See the Tagging section above.

LTS releases

For long-term support releases, " LTS" MAY be appended to the version number.

  • v1.0.0
  • v1.1.0
  • v1.2.0
  • v1.3.0 LTS
  • v1.4.0
  • v1.5.0
  • v2.0.0
  • v2.1.0 LTS
  • v2.2.0

Named releases

In addition to a version number, consumer-friendly release names such as "Autumn 2025" MAY be used for user-facing software applications.