Semantic Versioning (SemVer)
debt(d7/e3/b3/t5)
Closest to 'only careful code review or runtime testing' (d7). SemVer violations (breaking change in a patch) aren't caught by static tooling — semantic-release/conventional-changelog can automate versioning from commit messages, but if commits are mislabeled or contracts broken implicitly, only review or downstream breakage reveals it.
Closest to 'simple parameterised fix' (e3). The quick_fix is to adopt semantic-release/standard-version with conventional commits — a configuration-level change in one repo, not a code refactor, but more than a one-liner.
Closest to 'localised tax' (b3). Versioning policy applies at the package boundary; once tooling is wired in, it's a light ongoing tax on commit discipline and release process, not pervasive across the codebase.
Closest to 'notable trap most devs eventually learn' (t5). The misconception that SemVer is just numbering (rather than a behavioural contract) and that 0.x is stable are documented gotchas — surprising to newcomers but widely understood once encountered.
Also Known As
TL;DR
Explanation
SemVer (semver.org) specifies: increment PATCH for backwards-compatible bug fixes, MINOR for backwards-compatible new features, MAJOR for breaking changes. A caret (^) constraint in composer.json allows MINOR and PATCH updates but not MAJOR — this relies on authors following SemVer correctly. Pre-release versions use suffixes (1.0.0-alpha.1). Semantic versioning gives dependency managers a contract for safe automated upgrades and gives users a signal about migration effort. Violating SemVer (releasing breaking changes in a MINOR version) erodes consumer trust.
Common Misconception
Why It Matters
Common Mistakes
- Releasing breaking changes in minor or patch versions — this is the most damaging semver violation.
- Treating 0.x versions as stable — semver explicitly allows breaking changes in 0.x, which surprises consumers.
- Not tagging releases in version control — the tag is the canonical source of truth for what was released.
- Bumping the major version for every release out of caution — major version fatigue makes consumers stop updating.
Avoid When
- Releasing breaking changes as minor or patch versions — consumers rely on semver to automate safe upgrades.
- Using semver for internal APIs or single-consumer packages where a simple date or build number suffices.
- Treating v0.x as 'anything goes' without communicating this clearly — consumers assume stability.
When To Use
- Any library or package with external consumers — semver communicates compatibility guarantees precisely.
- Automated dependency update tools — Dependabot and Renovate use semver to determine safe auto-merge.
- CI pipelines — semver enables automated promotion of patch and minor updates without manual review.
- Changelog generation — conventional commits + semver automates release notes from commit history.
Code Examples
// Version bumped arbitrarily — consumers can't predict impact:
v1.2.3 → v1.2.4 // Breaking API change — should be v2.0.0
v1.2.3 → v2.0.0 // Minor bug fix — should be v1.2.4
// SemVer correctly:
// MAJOR.MINOR.PATCH
// MAJOR: breaking change
// MINOR: new feature, backward-compatible
// PATCH: bug fix, backward-compatible
# MAJOR.MINOR.PATCH — e.g. 2.4.1
# PATCH (2.4.1 → 2.4.2): backward-compatible bug fix
# MINOR (2.4.1 → 2.5.0): backward-compatible new feature
# MAJOR (2.4.1 → 3.0.0): breaking change — existing users must adapt
# composer.json version constraints
"require": {
"vendor/package": "^2.4", # >=2.4.0 <3.0.0 (recommended)
"vendor/package": "~2.4.1", # >=2.4.1 <2.5.0 (patch only)
"vendor/package": "2.4.*", # 2.4.x only
"vendor/package": ">=2.0 <3", # explicit range
}
# Tag a release in git
git tag -a v2.5.0 -m 'Add OAuth2 login'
git push origin v2.5.0