Question
Maven Dependency Versions: Latest Releases, Ranges, and Updates
Question
In Maven, dependencies are usually declared with a specific version:
<dependency>
<groupId>wonderful-inc</groupId>
<artifactId>dream-library</artifactId>
<version>1.2.3</version>
</dependency>
When a library has frequent releases, manually changing the <version> element can be inconvenient. Can Maven be configured to always use the latest available version from a repository?
Short Answer
You will learn how Maven chooses dependency versions, why fixed versions are normally the safest choice, and how to use version ranges, -SNAPSHOT versions, and Maven update tools appropriately.
Concept
Maven needs a version to identify exactly which artifact to download. A dependency coordinate is made of:
groupId: the organization or namespaceartifactId: the library nameversion: the particular library release
A fixed version is the standard and recommended approach:
<version>1.2.3</version>
It makes builds reproducible: the same source code can resolve to the same dependencies today, on a colleague's machine, and in CI.
Maven does support dynamic version selection, mainly through version ranges. For example:
<version>[1.2.3,)</version>
This means “select version 1.2.3 or any newer version.” Maven consults repository metadata to choose a matching release.
However, automatically selecting the newest version is usually a poor choice for production builds. A newly published version may contain a breaking API change, a regression, changed transitive dependencies, or a security-related behavior change. The same commit could build differently tomorrow without any change to your project.
Older Maven mechanisms named LATEST and RELEASE have historically existed, but they should not be used in modern projects. They create non-reproducible builds and are deprecated by Maven 3. Maven recommends explicit versions instead.
The practical workflow is:
- Pin a known version in
pom.xml. - Use a tool to discover available updates.
- Review release notes and compatibility.
- Update the pinned version intentionally.
- Run tests and commit the version change.
Mental Model
Think of a dependency version as the edition number of a textbook used by a class.
- A fixed version means everyone studies from the same edition. Page numbers, examples, and exercises stay consistent.
- “Latest edition” means the bookstore might give each student a different, newer book over time. Some pages may be removed or changed unexpectedly.
- A version range is like saying, “Give me any edition from the third edition onward.” It is flexible, but you no longer know exactly which book will arrive.
For reliable software builds, developers normally choose one known edition, then deliberately upgrade after checking what changed.
Syntax and Examples
A Maven dependency normally uses an exact version:
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.14.0</version>
</dependency>
This tells Maven to resolve exactly commons-lang3:3.14.0.
Version range syntax
Maven version ranges use brackets and parentheses:
<!-- 1.2.3 or any newer version -->
<version>[1.2.3,)</version>
<!-- Any version from 1.2.3 up to, but not including, 2.0.0 -->
<version>[1.2.3,2.0.0)</version>
<!-- Versions strictly newer than 1.2.3 and up to 2.0.0 -->
<version>(1.2.3,2.0.0]</version>
Rules:
[means the boundary is included.(means the boundary is excluded.)means the upper boundary is excluded.- An empty upper bound, as in
[1.2.3,), has no maximum.
A bounded range is less risky than an unbounded range, but it can still make builds change when repository metadata changes. Use ranges only when you understand and accept that trade-off.
Snapshot versions
A -SNAPSHOT version is for changing development builds:
<dependency>
<groupId>com.example</groupId>
<artifactId>shared-library</artifactId>
<version>2.1.0-SNAPSHOT</version>
</dependency>
Maven can check a snapshot repository for newer timestamped builds of that same snapshot line. A snapshot is not the same as “the latest release”; it is an in-development version and is generally unsuitable for stable releases.
Step by Step Execution
Consider this dependency range:
<dependency>
<groupId>com.example</groupId>
<artifactId>payment-client</artifactId>
<version>[2.4.0,3.0.0)</version>
</dependency>
Assume the repository contains these versions:
2.3.9
2.4.0
2.5.1
2.9.0
3.0.0
Maven resolves it as follows:
- Maven reads the lower bound:
[2.4.0means2.4.0is allowed. - Maven reads the upper bound:
3.0.0)means3.0.0itself is not allowed. - Maven discards
2.3.9because it is below the allowed range. - Maven accepts
2.4.0,2.5.1, and2.9.0. - Maven rejects
3.0.0because the closing parenthesis excludes it. - Maven selects the highest matching version:
2.9.0.
If 2.9.1 is published later, the same project may resolve 2.9.1 the next time Maven checks repository metadata. That changing result is why a fixed version is usually preferred.
Real World Use Cases
Application services
A web application should usually pin versions. Its CI pipeline and production deployment need to use the same tested dependency graph.
<version>5.3.31</version>
Internal libraries under active development
A team may temporarily consume an internal snapshot while two projects are being developed together:
<version>4.0.0-SNAPSHOT</version>
This is useful during development, but the team should publish and consume a stable release before production deployment.
Plugin or extension compatibility
A library intended to integrate with several compatible versions of another library may declare a bounded version range. This is more common for reusable libraries than for end-user applications, and it requires careful compatibility testing.
Maintenance and security updates
Rather than silently selecting newer versions, teams run update reports, inspect release notes and security advisories, then upgrade deliberately in a pull request.
Real Codebase Usage
Real Maven projects commonly centralize and control versions instead of using “latest.”
Use properties for easy updates
<properties>
<commons-lang3.version>3.14.0</commons-lang3.version>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>${commons-lang3.version}</version>
</dependency>
</dependencies>
Updating one property updates every dependency declaration that uses it.
Use dependency management
A parent POM can define versions once for many modules:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.14.0</version>
</dependency>
</dependencies>
</dependencyManagement>
Child modules can then omit the version:
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
Check for upgrades with the Versions Maven Plugin
Run this command to display dependencies that have newer versions:
mvn versions:display-dependency-updates
To update properties automatically, review the result carefully and use plugin goals that fit your project workflow. Automated edits should still be tested and code-reviewed.
Inspect the resolved dependency graph
When diagnosing an unexpected version, use:
mvn dependency:tree
This shows direct and transitive dependencies and helps identify version conflicts or overrides.
Common Mistakes
Using LATEST or RELEASE
Avoid this older style:
<version>LATEST</version>
or:
<version>RELEASE</version>
These values lead to unpredictable builds and are deprecated in Maven 3. Pin a version and update it intentionally.
Using an unbounded range everywhere
This works syntactically:
<version>[1.0,)</version>
But it allows any future major release, including one with breaking changes. If a range is genuinely necessary, prefer a bounded one such as:
<version>[1.0,2.0)</version>
Expecting a range to ignore the local cache
Maven stores artifacts and metadata in the local repository. A range may not appear to change on every build because Maven can use cached metadata. Do not rely on cache behavior as a version-management strategy.
Treating snapshots as stable releases
A snapshot can change while keeping the same visible version, such as 2.0.0-SNAPSHOT. Do not use snapshots for a reproducible production release.
Forgetting transitive dependencies
Updating one library can update its transitive dependencies too. Run tests and inspect the result:
mvn dependency:tree
Assuming Maven always chooses the version you wrote
When multiple dependency paths request different versions, Maven uses dependency mediation rules. A direct dependency or a version declared in dependencyManagement can affect the final resolved version.
Comparisons
| Approach | Example | Best use | Main trade-off |
|---|---|---|---|
| Fixed version | 3.14.0 | Applications and production builds | Requires a deliberate update |
| Bounded range | [1.2.0,2.0.0) | Carefully tested compatibility windows | Resolved version can change over time |
| Unbounded range | [1.2.0,) | Rarely appropriate | Future breaking versions can be selected |
| Snapshot | 2.0.0-SNAPSHOT | Active internal development | Build contents can change without a version change |
LATEST / RELEASE | LATEST | Do not use | Deprecated and non-reproducible |
A fixed version is not “more work” in a harmful sense: it records an intentional, reviewable dependency decision. Properties, parent POMs, and update-report tools reduce the maintenance effort.
Cheat Sheet
Recommended default
<dependency>
<groupId>com.example</groupId>
<artifactId>example-library</artifactId>
<version>1.2.3</version>
</dependency>
Range notation
| Syntax | Meaning |
|---|---|
[1.0] | Exactly 1.0 |
[1.0,2.0] | From 1.0 through 2.0 |
[1.0,2.0) | From 1.0, excluding 2.0 |
(1.0,2.0] | After 1.0, through 2.0 |
[1.0,) | 1.0 or newer |
Useful commands
# List available dependency updates
mvn versions:display-dependency-updates
# Show resolved direct and transitive dependencies
mvn dependency:tree
Rules of thumb
- Pin release versions for reproducible builds.
- Avoid
LATESTandRELEASE. - Treat
-SNAPSHOTas changing development output. - Use
dependencyManagementor properties to centralize versions. - Test every dependency upgrade.
FAQ
Can Maven always download the latest dependency version?
Maven can resolve version ranges, but automatically using the newest version is not recommended for normal builds because it makes results non-reproducible.
What replaced LATEST and RELEASE in Maven?
There is no recommended direct replacement for always using the newest version. Use fixed versions and the Versions Maven Plugin to discover upgrades. Version ranges exist, but should be used cautiously.
How do I see newer Maven dependency versions?
Run:
mvn versions:display-dependency-updates
Then choose, test, and commit an appropriate upgrade.
What does [1.2.3,) mean in Maven?
It is a version range that accepts 1.2.3 and every higher version Maven finds. It can unexpectedly select a future major version.
Is a Maven snapshot the latest version?
No. A snapshot is an in-development build for one specific version line, such as 1.5.0-SNAPSHOT. It is not necessarily the newest stable release.
Why did Maven resolve a different transitive dependency version than I expected?
Several dependencies can request different versions of the same artifact. Maven applies dependency mediation and dependency-management rules to select one version. Use mvn dependency:tree to investigate.
Should libraries use Maven version ranges?
Sometimes, but only when the library has tested compatibility across that range. Applications usually benefit more from fixed, explicitly tested versions.
Mini Project
Description
Create a small multi-module-style Maven configuration that centralizes a library version, then use Maven to inspect available upgrades and the resolved dependency tree. This mirrors a common maintenance task in Java projects.
Goal
Manage a dependency with a fixed, centrally defined version and verify what Maven resolves.
Requirements
- Create a Maven project with a valid
pom.xml. - Define the dependency version in a Maven property.
- Add Apache Commons Lang as a dependency using that property.
- Add a small Java class that uses
StringUtils. - Run the application or its tests successfully.
- Run Maven commands to view dependency updates and the dependency tree.
Keep learning
Related questions
Add External JAR Files to an IntelliJ IDEA Java Project
Learn how to add external JAR dependencies to an IntelliJ IDEA Java project using module libraries, and when to use Maven or Gradle instead.
Avoiding Java Code in JSP with JSP 2: EL and JSTL Explained
Learn how to avoid Java scriptlets in JSP 2 using Expression Language and JSTL, with examples, best practices, and common mistakes.
Call a Method After a Delay in Android Java
Learn how to run Java code after a delay in Android using Handler.postDelayed, manage the main thread, and cancel callbacks safely.