Maven’s dependency management automatically resolves transitive dependencies and ensures consistent versions across a project.

Declaring Dependencies

  <dependencies>
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter</artifactId>
        <version>5.10.0</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>com.google.guava</groupId>
        <artifactId>guava</artifactId>
        <version>33.0.0-jre</version>
    </dependency>
</dependencies>
  

Dependency Scopes

Scope Compile Test Runtime Example
compile (default) Guava, Spring
test JUnit, Mockito
runtime JDBC driver
provided Servlet API (container provides)
system Local JAR (avoid)
import BOM import only

Transitive Dependencies

Maven resolves dependencies recursively. If A depends on B, and B depends on C, your project gets C automatically:

  my-app → spring-boot-starter-web → spring-web → spring-core
  

View the tree:

  mvn dependency:tree
mvn dependency:tree -Dincludes=com.google.guava
  

Exclusions

Remove unwanted transitive dependencies:

  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <exclusions>
        <exclusion>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
        </exclusion>
    </exclusions>
</dependency>
  

Dependency Management (BOM)

Centralize version control without adding dependencies:

  <dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>3.2.0</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

<!-- Now declare without version -->
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
</dependencies>
  

Version Conflicts

When two dependencies require different versions of the same artifact, Maven uses nearest definition (shortest path in the tree).

Force a specific version:

  <dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>33.0.0-jre</version>
        </dependency>
    </dependencies>
</dependencyManagement>
  

Best Practices

  • Use BOM/dependencyManagement to control versions centrally
  • Prefer test scope for test-only libraries
  • Run mvn dependency:tree to diagnose conflicts
  • Avoid system scope — use a proper repository instead
  • Keep dependencies minimal — remove unused ones regularly