How do Maven version ranges work (e.g. [1.0,2.0)), and why are pinned versions usually preferred?
answer
- [ ] inclusive, ( ) exclusive
- range picks HIGHEST match
- bare version = soft, [x] = hard
- ranges break reproducibility
- pin + BOM + deliberate upgrades
basics
~20 sA version range like [1.0,2.0) lets Maven pick any matching version: square brackets are inclusive, parentheses exclusive. So that means >=1.0 and <2.0. Most teams instead pin an exact version (e.g. 1.4.2) for reproducible, predictable builds.
solid answer
~40 sMaven supports mathematical-interval ranges: [ ] are inclusive bounds, ( ) exclusive. [1.0,2.0) means >=1.0 and <2.0; [1.5,] means >=1.5; (,1.0] means <=1.0; [1.2] means exactly 1.2 (a hard pin). At resolution Maven reads maven-metadata.xml and selects the highest version in the range. The catch: ranges make builds non-deterministic — a new release in the range can change your build without any pom edit, breaking reproducibility and inviting surprise breakage or supply-chain risk. They also interact awkwardly with mediation. A plain version like '1.4.2' is technically a 'soft' requirement (a recommendation that mediation can override), whereas '[1.4.2]' is a 'hard' pin. In practice teams pin exact versions, centralize them in dependencyManagement/BOMs, and upgrade deliberately via tooling like the versions plugin or Dependabot rather than relying on ranges.
code
xml · 6 lines<!-- [1.0,2.0): >=1.0 and <2.0; Maven picks the highest match -->
<dependency>
<groupId>org.example</groupId>
<artifactId>lib</artifactId>
<version>[1.0,2.0)</version>
</dependency>go deeper
Recognizes the bracket/parenthesis inclusive-exclusive syntax.
Knows ranges pick the highest match and reads maven-metadata.xml.
Articulates soft-vs-hard requirements and why pinning beats ranges for reproducibility/security.
Sets org policy: pin + BOM, ban ranges in app builds, drive upgrades via tooling and supply-chain controls.
## Range syntax (interval notation) Maven borrows math interval notation: - `[ ]` = **inclusive** bound - `( )` = **exclusive** bound - comma separates lower,upper; an empty side means unbounded. Examples: - `[1.0,2.0)` → 1.0 <= v < 2.0 - `[1.5,]` → v >= 1.5 - `(,1.0]` → v <= 1.0 - `[1.2,1.3]` → 1.2 <= v <= 1.3 - `[1.2]` → exactly 1.2 (a HARD requirement) ## Soft vs hard requirements A bare version such as `1.4.2` is a **soft** requirement: it's your recommendation, but Maven's dependency mediation (nearest-wins) can override it with another version chosen for a transitive conflict. Wrapping it as `[1.4.2]` makes it a **hard** requirement that must be satisfied exactly, or the build fails. ## How a range resolves Maven fetches `maven-metadata.xml` for the artifact, looks at the available versions, and picks the **highest** version that falls inside the range (release versions; SNAPSHOTs only if enabled). Because new releases appear over time, the same pom can resolve differently next week. ## Why pinned versions are preferred - **Reproducibility**: today's build == next year's build. A range can silently pull a newer, incompatible release. - **Stability/security**: a malicious or buggy new release in-range gets picked up automatically (supply-chain risk). - **Debuggability**: 'it worked yesterday' bugs from invisible version drift are painful. - **Mediation clarity**: ranges complicate conflict resolution. Best practice: pin exact versions, centralize them in `<dependencyManagement>`/BOMs, and bump them explicitly with tooling. ```xml <!-- avoid in app code --> <dependency> <groupId>org.example</groupId> <artifactId>lib</artifactId> <version>[1.0,2.0)</version> </dependency> <!-- prefer: explicit, reproducible --> <dependency> <groupId>org.example</groupId> <artifactId>lib</artifactId> <version>1.4.2</version> </dependency> ``` ## Where ranges still appear Some libraries (especially shared API contracts or plugins) publish ranges to express compatibility windows, and OSGi-style ecosystems use them more. But for application builds, pinning is the norm. To find/upgrade versions deliberately, use `versions:display-dependency-updates` from the versions-maven-plugin.
- What's the difference between version '1.4.2' and '[1.4.2]'?'1.4.2' is a soft requirement that mediation can override; '[1.4.2]' is a hard pin that must be satisfied exactly or the build fails.
- Within a range, which version does Maven choose?The highest available version that falls inside the range (per maven-metadata.xml).
- Why do most teams avoid ranges in application builds?They make builds non-reproducible and add supply-chain/stability risk, since a new in-range release changes the build with no pom edit.
saying these in an interview costs you the question
- Saying parentheses are inclusive and brackets exclusive (it's the reverse).
- Claiming a range picks the lowest matching version (it picks the highest).
- Recommending ranges for reproducible production builds.
- Thinking a bare version is always honored regardless of mediation.