Semantic Versioning and Gem Constraints
Fast recall
Quick revision
Core answer
MAJOR.MINOR.PATCH to describe changes to a declared public API: major for incompatible changes, minor for backward-compatible features, and patch for backward-compatible fixes. A 0.y.z release is initial development and may change at any time; pre-release identifiers sort before the normal release, while build metadata does not affect precedence. Gem constraints express versions an application permits, but they cannot guarantee a gem author followed SemVer correctly—tests and lockfile review still matter.Whether you know MAJOR.MINOR.PATCH and what triggers each bump (breaking/feature/bugfix) and that '~> 2.4' trusts it.
Treating every version bump as risky (MINOR/PATCH should be safe), or bumping MAJOR for a small change (reserve it for breaking changes).
SemVer = MAJOR.MINOR.PATCH. MAJOR: breaking change; MINOR: new feature (compatible); PATCH: bug fix. '~> 2.4' allows MINOR/PATCH, blocks MAJOR.
Interview-ready guide
Interview answer
Semantic Versioning gives release numbers meaning relative to a declared public API. In MAJOR.MINOR.PATCH, a backward-incompatible API change increments major, backward-compatible functionality increments minor, and a backward-compatible bug fix increments patch. Advancing a higher component resets the lower components to zero.
For example, changing Invoice#total so existing callers need a new required argument is a major change. Adding an optional currency formatter without breaking callers can be minor, and correcting an incorrect rounding result without changing the contract can be patch.
SemVer has boundaries people often miss. Versions below 1.0.0 represent initial development and may change at any time. A version such as 2.0.0-rc.1 has lower precedence than 2.0.0; build metadata after +, such as 2.0.0+sha.abc, does not affect precedence.
RubyGems constraints use these numbers to describe an accepted range. ~> 2.3 allows later 2.x releases below 3.0, while ~> 2.3.4 stays below 2.4. The application's lockfile then records one exact chosen release until an intentional update.
SemVer is a communication contract, not an automatic proof of compatibility. A maintainer can misclassify a breaking change or an application can rely on undocumented behaviour, so dependency upgrades still need changelog review, tests, and a controlled lockfile change.
Semantic Versioning and Gem Constraints
Direct Answer
Semantic Versioning uses MAJOR.MINOR.PATCH to describe changes to a declared public API: major for incompatible changes, minor for backward-compatible features, and patch for backward-compatible fixes. A 0.y.z release is initial development and may change at any time; pre-release identifiers sort before the normal release, while build metadata does not affect precedence. Gem constraints express versions an application permits, but they cannot guarantee a gem author followed SemVer correctly—tests and lockfile review still matter.
Deep Dive & Architecture
SemVer works only when a project can identify its public API. That API may be code, a command-line interface, a data format, or documented behaviour. Refactoring private internals can remain a patch when users observe no changed contract; a one-line public removal can require a major release.
Pre-release identifiers communicate that a version may not satisfy the compatibility expectations of its normal release. Their parts participate in precedence comparisons. Build metadata identifies a build but is deliberately ignored for precedence, so two builds differing only after + have equal SemVer precedence.
A dependency range converts the upstream promise into local upgrade policy. A wide range makes fixes and features easier to receive but trusts more future releases. A narrow range reduces surprise but increases manual maintenance and resolution conflict. An application lockfile separates permission from timing by recording exactly when one allowed release was adopted.
Compatibility is contextual. Even a correct patch release can expose an application's accidental dependence on a bug, timing, or private API. Automated tests, deprecation review, and staged deployment are the evidence that a permitted version is safe for this application.
Code Example
require 'rubygems'
minor_range = Gem::Requirement.new('~> 2.3')
patch_range = Gem::Requirement.new('~> 2.3.4')
minor_range.satisfied_by?(Gem::Version.new('2.9.0')) # => true
minor_range.satisfied_by?(Gem::Version.new('3.0.0')) # => false
patch_range.satisfied_by?(Gem::Version.new('2.3.9')) # => true
patch_range.satisfied_by?(Gem::Version.new('2.4.0')) # => false
Common Mistakes & Pitfalls
Treating every version bump as risky (MINOR/PATCH should be safe), or bumping MAJOR for a small change (reserve it for breaking changes).
Check your understanding
Answer these without looking back at the article.
- What must a project define before SemVer has useful meaning?
- How do pre-release labels and build metadata affect precedence differently?
- Why can a SemVer-compatible dependency update still break an application?
Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.