5.4 Dependency Versioning: SemVer, CalVer & Automated Versioning
Key Takeaways
- SemVer increments MAJOR for breaking changes, MINOR for backwards-compatible features and PATCH for backwards-compatible fixes.
- A pre-release identifier after a hyphen (1.2.0-beta.1) sorts lower than the release version, while build metadata after a plus sign (1.2.0+build.42) is ignored entirely for precedence.
- CalVer suits products whose value is recency rather than API compatibility, such as operating system images, browser builds and data snapshots.
- GitVersion derives the version from branch name, tags and commit height, and supports Mainline, ContinuousDelivery and ContinuousDeployment modes.
- Nerdbank.GitVersioning stores the base version in version.json and derives a deterministic build height, giving reproducible versions across microservice repositories.
5.4 Dependency Versioning: SemVer, CalVer & Automated Versioning
Quick Summary: Consistent versioning is the operational backbone of enterprise dependency management. In Exam AZ-400, candidates must understand the formal specifications and trade-offs between Semantic Versioning (SemVer 2.0.0) and Calendar Versioning (CalVer), including the exam-critical distinction between pre-release identifiers and build metadata, and must automate version generation with tools such as GitVersion and Nerdbank.GitVersioning. Pipeline artifact versioning and transport follow in Section 5.5.
The Technical Specification of Semantic Versioning (SemVer 2.0.0)
In microservice architectures and shared library ecosystems, consumers require clear, machine-readable guarantees regarding whether updating a dependency will break existing functionality. Semantic Versioning (SemVer 2.0.0) provides a formal three-part numerical specification:
MAJOR . MINOR . PATCH [ - PRERELEASE ] [ + BUILDMETADATA ]
Examples:
1.4.2
2.0.0-rc.1
3.1.0-alpha.20260905.1
2.4.0+sha.7f8a9b
The Rules of Version Incrementation
MAJOR(Breaking Changes): Incremented when incompatible API changes are introduced that require consumers to alter their calling code. Examples include modifying method signatures, removing classes or REST endpoints, dropping supported protocol versions, or changing database schema contracts. WhenMAJORincrements,MINORandPATCHmust be reset to 0 (e.g.,1.8.4->2.0.0).MINOR(Backwards-Compatible New Features): Incremented when new, backwards-compatible functionality is added to the public API. Examples include adding an optional parameter to a function, exposing a new REST endpoint, or introducing an overload. WhenMINORincrements,PATCHmust be reset to 0 (e.g.,2.1.3->2.2.0).PATCH(Backwards-Compatible Defect Repairs): Incremented when backwards-compatible bug fixes or internal performance optimizations are introduced without altering the public API contract (e.g.,2.2.0->2.2.1).
Pre-Release Identifiers vs. Build Metadata (The Critical Exam Distinction)
SemVer 2.0.0 supports optional suffixes that behave fundamentally differently during dependency resolution:
SemVer Suffix Precedence Comparison:
[Pre-Release Identifier] [Build Metadata]
- Syntax: -alpha, -beta.1, -rc.2 - Syntax: +20260905.1, +sha.8f2a1b
- Impacts Precedence? YES - Impacts Precedence? NO (Ignored!)
- Rule: Pre-release < Normal Version - Rule: 1.0.0+A has EQUAL precedence to 1.0.0+B
- Order: 1.0.0-alpha < 1.0.0-rc.1 < 1.0.0 - Used for: Diagnostic build tracing only
- Pre-Release Identifiers (
-hyphen): Denotes unstable packages that precede a formal release. Precedence is determined lexically and numerically across dot-separated identifiers. A pre-release version has lower precedence than the associated normal version:1.0.0-alpha < 1.0.0-alpha.1 < 1.0.0-beta < 1.0.0-beta.2 < 1.0.0-rc.1 < 1.0.0 - Build Metadata (
+plus sign): Appends diagnostic build details (such as build IDs, CI run numbers, or Git commit SHAs). Build metadata is strictly ignored when determining version precedence! Two versions that differ only in build metadata have identical precedence in NuGet, npm, and Maven:1.4.0+build.1 === 1.4.0+build.2 (Equal precedence)
[!WARNING] AZ-400 Exam Trap: A question may ask which package version will be restored when a consumer specifies
>= 1.2.0. If the feed contains1.2.0and1.2.0+20260905, package managers treat them as equivalent. If a team attempts to publish1.2.0+build2after1.2.0+build1, Azure Artifacts will reject the upload with409 Conflictbecause the underlying immutable SemVer is identical (1.2.0).
Calendar Versioning (CalVer): Practical Applications
While SemVer is ideal for programmatic APIs and libraries, Calendar Versioning (CalVer) bases version identifiers on release dates and schedules.
CalVer Format Anatomy
CalVer strings combine temporal segments with micro/patch counters:
YYYY.MM.MICRO(e.g.,2026.09.1): Full four-digit year, zero-padded month, incremental release counter.YY.0M.0D(e.g.,26.09.05): Short year, zero-padded month and day.YYYY.WW(e.g.,2026.36): Year and calendar week number.
When CalVer Outperforms SemVer
- End-User Applications & Operating Systems: Ubuntu (
24.04 LTS), Windows (23H2), and macOS use date-based naming because users and enterprise IT administrators care about support lifecycles, release recency, and end-of-life (EOL) deadlines rather than public API breaking changes. - Command-Line Tools & Utilities: Tools like Azure CLI (
2.58.0) or pip incorporate CalVer or hybrid models where releases occur on regular cadence. - Continuous Deployment SaaS & Microservices: When services deploy continuously to production multiple times daily and do not expose shared binary libraries, date-based versions (e.g.,
2026.09.05.3) communicate deployment timing far more effectively than arbitrary SemVer increments.
SemVer vs. CalVer Comparison Matrix
| Criteria | Semantic Versioning (SemVer) | Calendar Versioning (CalVer) |
|---|---|---|
| Core Philosophy | Communicates API compatibility and breaking risk | Communicates temporal recency and support lifespan |
| Primary Use Case | Shared libraries, SDKs, APIs, public frameworks | End-user apps, CLI tools, SaaS services, OS distributions |
| Increment Trigger | Code change impact (breaking vs. feature vs. bug fix) | Calendar date progression / scheduled sprint cadence |
| Downstream Impact | Informs automated package manager upgrade ranges (^, ~) | Informs human operators of product lifecycle and age |
| Tooling Support | Native in NuGet, npm, Maven, PyPI, Cargo | Custom parsing or string comparisons in packaging tools |
Automated Versioning Tools: GitVersion & Nerdbank.GitVersioning
In modern DevOps, manually modifying version numbers in source code files (package.json, .csproj, pom.xml) is a major anti-pattern. Manual editing causes frequent merge conflicts across feature branches, human versioning errors, and non-reproducible releases. Instead, versioning should be derived automatically from the source control graph.
1. GitVersion
GitVersion is an open-source tool that executes inside CI/CD pipelines to calculate SemVer dynamically by inspecting Git history, commit tags, and branch names.
GitVersion Branch Topology & Version Derivation:
main ──o──[Tag: v1.2.0]─────────────────────o (Version: 1.3.0)
\ /
release/1.3 o──o (1.3.0-beta.1)
\
feature/auth o──o (1.3.0-auth.1+2)
- GitVersion Modes:
- Continuous Delivery Mode (Default): Calculates the version that will be published when the branch is next merged. Commits on a feature branch generate pre-release tags (e.g.,
1.3.0-feature-auth.2). Merging intomaincreates a release version (1.3.0). - Continuous Deployment Mode: Increments the patch or pre-release number with every single commit, ensuring every push generates a strictly increasing unique version.
- Continuous Delivery Mode (Default): Calculates the version that will be published when the branch is next merged. Commits on a feature branch generate pre-release tags (e.g.,
- Configuration (
GitVersion.yml): Defines branch increment rules, tag prefixes, and formatting strategies:
# GitVersion.yml configuration
mode: ContinuousDelivery
next-version: 2.0.0
branches:
main:
regex: ^master$|^main$
mode: ContinuousDelivery
tag: ''
increment: Patch
feature:
regex: ^features?[/-]
mode: ContinuousDeployment
tag: useBranchName
increment: Inherit
- Azure Pipelines Integration: GitVersion provides dedicated tasks (
gitversion/setup@0andgitversion/execute@0) that export environment variables (such as$(GitVersion.SemVer)and$(GitVersion.NuGetVersion)) directly into the pipeline context.
2. Nerdbank.GitVersioning (NBGV)
Nerdbank.GitVersioning is an ultra-fast, lightweight versioning tool widely used in enterprise .NET and cloud repositories:
- Uses a single
version.jsonfile in the root of the repository declaring the base version (e.g.,"version": "2.1"). - Calculates the third component (PATCH or build number) using Git commit height (
git rev-list --count), guaranteeing that every commit in the repository produces a deterministic, strictly increasing, non-colliding version number.
A software team publishes internal npm packages adhering to Semantic Versioning (SemVer 2.0.0). A consuming application configures its package dependency constraint as '^1.4.2'. The private feed currently contains versions '1.4.2', '1.4.3', '1.5.0', '1.5.1-beta.1', '2.0.0', and '1.5.0+build.20260905'. Which version will the package manager resolve and install when executing 'npm install'?
A DevOps team wants to automate version numbering across multiple microservice repositories in Azure Pipelines. They require that every pipeline execution calculates a strictly increasing, non-colliding Semantic Version based on Git branch topology, tags, and commit history, without requiring developers to manually edit version strings in repository files before submitting pull requests. Which tool natively satisfies this requirement?