Skip to main content

Maven Project

Managing Dependencies in Maven

Learn how to manage dependencies in Maven. Understand how to add dependencies in pom.xml, explore dependency scopes (compile, provided, runtime, test), and see how Maven resolves transitive dependencies.

One of the most powerful features of Apache Maven is its ability to manage project dependencies automatically.
Instead of manually downloading JAR files and placing them in your project, Maven allows you to declare them in a simple pom.xml file, and it fetches everything you need from the Maven Central Repository.

In this lesson, you’ll learn:

  • How to add dependencies to your Maven project
  • Different dependency scopes and when to use them
  • How Maven handles transitive dependencies

1. Adding Dependencies to pom.xml

Every Maven project has a pom.xml file at its root. This is where you declare all the libraries (dependencies) your project needs.

Adding JUnit Dependency

<dependencies>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.13.2</version>
        <scope>test</scope>
    </dependency>
</dependencies>
  • groupId → Identifies the organization/project (e.g., junit)
  • artifactId → The library name (e.g., junit)
  • version → Specific version of the library
  • scope → Defines how/when this dependency is used

📌 Tip: You can search dependencies at Maven Central Repository.

2. Dependency Scopes in Maven

Maven provides different scopes to control when a dependency is available (compile time, runtime, testing, etc.).

ScopeAvailable AtUse Case Example
compile (default)Compile, runtime, and test phasesMost application libraries (e.g., Spring, Hibernate)
providedCompile only (not packaged)Servlet API in web apps (provided by Tomcat/Jetty)
runtimeRuntime and test (not needed for compile)JDBC drivers, logging frameworks
testTest phase onlyJUnit, Mockito, TestNG
systemSimilar to provided, but requires explicit local path (not recommended)Legacy projects with non-Maven JARs

Example: Provided Scope (Servlet API)

<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>4.0.1</version>
    <scope>provided</scope>
</dependency>

This ensures the servlet API is available during compilation, but it won’t be included in your WAR file because the application server already provides it.

3. Transitive Dependencies

Maven not only downloads the dependencies you explicitly declare but also their transitive dependencies (the libraries your libraries depend on).

Example: Spring Boot Starter Web

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <version>3.1.0</version>
</dependency>

Adding just this one dependency pulls in:

  • Spring Web MVC
  • Jackson (for JSON processing)
  • Tomcat (as the embedded servlet container)
  • Logging frameworks

This saves you time because you don’t need to manually add every single dependency.

4. Handling Dependency Conflicts

Sometimes, transitive dependencies may include different versions of the same library.
To check this, use:

mvn dependency:tree

If there’s a version conflict, you can override it in your pom.xml by explicitly declaring the desired version:

<dependency>
    <groupId>commons-logging</groupId>
    <artifactId>commons-logging</artifactId>
    <version>1.2</version>
</dependency>

Key Takeaways

  • Dependencies are declared inside the <dependencies> section of pom.xml.
  • Use scopes (compile, provided, runtime, test) to control when dependencies are available.
  • Maven automatically manages transitive dependencies, but you should monitor for conflicts.
  • The mvn dependency:tree command helps debug and resolve version issues.