Question

Maven Dependency Versions: Latest Releases, Ranges, and Updates

javamavendependenciesmaven-2maven-metadata

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 namespace
  • artifactId: the library name
  • version: 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:

  1. Pin a known version in pom.xml.
  2. Use a tool to discover available updates.
  3. Review release notes and compatibility.
  4. Update the pinned version intentionally.
  5. 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.

Take Quiz

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:

  1. Maven reads the lower bound: [2.4.0 means 2.4.0 is allowed.
  2. Maven reads the upper bound: 3.0.0) means 3.0.0 itself is not allowed.
  3. Maven discards 2.3.9 because it is below the allowed range.
  4. Maven accepts 2.4.0, 2.5.1, and 2.9.0.
  5. Maven rejects 3.0.0 because the closing parenthesis excludes it.
  6. 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.

Take Quiz

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

ApproachExampleBest useMain trade-off
Fixed version3.14.0Applications and production buildsRequires a deliberate update
Bounded range[1.2.0,2.0.0)Carefully tested compatibility windowsResolved version can change over time
Unbounded range[1.2.0,)Rarely appropriateFuture breaking versions can be selected
Snapshot2.0.0-SNAPSHOTActive internal developmentBuild contents can change without a version change
LATEST / RELEASELATESTDo not useDeprecated 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.

Take Quiz

Cheat Sheet

Recommended default

<dependency>
  <groupId>com.example</groupId>
  <artifactId>example-library</artifactId>
  <version>1.2.3</version>
</dependency>

Range notation

SyntaxMeaning
[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 LATEST and RELEASE.
  • Treat -SNAPSHOT as changing development output.
  • Use dependencyManagement or 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.

Take Quiz

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.
Take Quiz

Keep learning

Related questions

View more