Semantic Versioning
debt(d7/e3/b5/t5)
Closest to 'only careful code review or runtime testing' (d7) — tools like semantic-release and conventional-changelog can automate versioning if adopted, but detecting that a MINOR bump actually contains breaking changes requires human review of the diff or downstream breakage; composer won't flag it.
Closest to 'simple parameterised fix' (e3) — the quick_fix is adopting a strict semver policy and bumping correctly going forward; if a bad release already shipped, you yank and re-release under the correct major, which is a small versioning fix rather than a cross-file refactor.
Closest to 'persistent productivity tax' (b5) — versioning discipline applies to every release across web and cli contexts and shapes how every consumer pins dependencies; mistakes propagate to all downstream users, but it doesn't define system architecture.
Closest to 'notable trap (documented gotcha)' (t5) — the misconception that PATCH can include small behavioural changes is widespread; most devs eventually learn that any observable change is at minimum MINOR, but it's a well-known gotcha rather than an inversion of similar concepts.
Also Known As
TL;DR
Explanation
SemVer 2.0: MAJOR.MINOR.PATCH. MAJOR: incompatible API changes. MINOR: new functionality, backwards compatible. PATCH: bug fixes, backwards compatible. Pre-release: 1.0.0-alpha.1, 1.0.0-beta.2, 1.0.0-rc.1 — lower precedence than release. Build metadata: 1.0.0+build.123 — ignored in precedence. Caret (^1.2.3): allows MINOR and PATCH updates. Tilde (~1.2.3): allows only PATCH updates. SemVer with Conventional Commits enables automated changelog generation and version bumping (semantic-release, changesets).
Common Misconception
Why It Matters
Common Mistakes
- Releasing breaking changes as MINOR — any dependency that allows ^1.x automatically gets the breaking change.
- Not starting at 1.0.0 for stable public APIs — 0.x means no stability guarantees; release 1.0.0 when the API is stable.
- Version 0.0.1 for everything — arbitrary version numbers without semantic meaning defeat the system.
- Not using pre-release versions for testing — release 2.0.0-beta.1 before 2.0.0 to allow early adopters to test.
Code Examples
# Breaking change released as MINOR — breaks consumers:
# Version 1.5.0: renamed method process() to run()
# Composer allows: ^1.0 (caret = any 1.x)
# Consumer runs: composer update
# Gets 1.5.0: their code calling process() breaks
# Correct version: 2.0.0 (MAJOR — breaking change)
# Correct versioning:
# Bug fix: 1.2.3 → 1.2.4 (PATCH)
# New optional parameter: 1.2.3 → 1.3.0 (MINOR)
# Renamed method: 1.2.3 → 2.0.0 (MAJOR)
# composer.json:
"require": {
"vendor/lib": "^2.0" # Allows 2.0.0 through 2.x.x
"vendor/lib": "~2.1.0" # Allows 2.1.0 through 2.1.x only
}
# Changelog driven by Conventional Commits:
# feat: → MINOR bump
# fix: → PATCH bump
# feat!: or BREAKING CHANGE: → MAJOR bump