A plain Maven version such as 1.0 is a soft requirement. Brackets make a hard requirement, and a range picks the highest version that fits. Ranges work, but they make builds depend on what exists in the repository today, so most teams use exact versions and manage upgrades deliberately.
The syntax, from the Maven documentation
Maven's POM reference says version requirements can be soft or hard. A soft requirement can be replaced by a different version of the same artifact found elsewhere in the dependency graph. A hard requirement mandates a version or versions and overrides soft requirements. If no version satisfies all the hard requirements, the build fails.
| Written as | Meaning |
|---|---|
| 1.0 | Soft requirement: use 1.0 if nothing earlier in the tree says otherwise |
| [1.0] | Hard requirement: 1.0 and only 1.0 |
| [1.0,2.0) | Hard: 1.0 up to but not including 2.0 |
| [1.5,) | Hard: 1.5 or higher |
| (,1.0],[1.2,) | Hard: anything except versions between 1.0 and 1.2 |
Maven picks the highest version of each project that satisfies all the hard requirements. The reference even shows excluding exactly one version, for example because it has a critical vulnerability.
Why ranges cost you repeatability
With a range, the resolved version depends on what has been published. A build today and a build next month can differ with no change to your POM. That is hard to debug and hard to audit, and it lets a new release enter your build without a pull request.
Soft requirements have their own surprise. Because another dependency elsewhere in the tree can override them, the version you wrote is not always the version you get. If it matters, check the effective result rather than assuming.
mvn dependency:tree
What most teams do instead
- Use exact versions in dependencies and centralize them in dependency management, so one place decides.
- Use a hard exact requirement when you must stop another path from changing it.
- Use a range only for deliberately flexible internal libraries, and prefer excluding one known bad version over opening a whole range.
- Raise versions through reviewed pull requests, not through the repository's state.
- Keep SNAPSHOT versions out of releases. They are for development.
Version ordering catches people
Maven compares versions by its own rules, not plain string order. The documentation lists qualifier order: alpha, beta, milestone, rc, snapshot, then a release with no qualifier, then sp. So a release candidate sorts before the final release, and a snapshot sorts before its release. Following semantic versioning is encouraged, and some qualifiers are discouraged, such as using final or ga as a suffix.
Hardening beyond versions
Version control is only half of it. Gradle has a separate verification feature for checksums and signatures, so check what your own build enforces about the files it downloads.
Where Safeguard fits
Safeguard's dependency scanning and SBOM generation can show the versions your Maven build resolves and which known vulnerabilities affect them, and a free scan is at gold.safeguard.sh/scan. Autonomous remediation can open fix pull requests, and it is off by default.
Try it yourself
Open the demo and follow how a vulnerable version is found, prioritized and tracked to a fix.
Click through it at your own pace, or open it full screen.
Quick check
What does a plain 1.0 mean in a Maven POM?
It is a soft requirement. Maven uses 1.0 unless another version appears earlier or is demanded by a hard requirement elsewhere in the tree.
Can I exclude one bad version?
Yes. The POM reference shows a range that excludes a single version, for example one with a critical vulnerability.
Sources
- Apache Maven: POM Reference (dependency version requirements)
- Apache Maven Enforcer: Version range specification
Last reviewed: 19 October 2026.