🎉 GoReplay is now part of Probe Labs. 🎉

Published on 8/16/2026

Maven Dependency Tree Command: Ultimate Guide to Analysis & Resolution

- A clean, high-tech developer desk scene with a softly blurred terminal window showing faint tree-like dependency diagrams in the background, featuring 'Dependency Tree' text centered on a solid background block in the golden ratio position, with subtle network node patterns framing the scene to convey analysis and resolution

If you’ve ever worked on a Maven project, you’ve felt the pain of dependency management. Things can get tangled fast. The one command that cuts right through the noise is mvn dependency:tree.

Running this command from your project’s root directory gives you a complete, top-to-bottom view of every library your application depends on—especially the ones you didn’t add yourself.

Why the Dependency Tree Is Your Most Important Tool

A laptop displays a 'Dependency Tree' diagram with a plant, mug, and sticky notes on a wooden desk.

When you pull a library into your pom.xml, you’re not just getting one file. You’re also inheriting its entire network of dependencies. We call these transitive dependencies, and they’re the primary cause of what developers everywhere know as “dependency hell.”

This isn’t some abstract concept; a messy dependency graph creates real-world headaches that slow down teams and introduce risk. Without a clear map of what’s inside your project, you’re flying blind into:

  • Version Conflicts: Two libraries you need might rely on different, incompatible versions of the same third-party library.
  • Bloated Artifacts: All those extra transitive dependencies can balloon the size of your final JAR or WAR, hurting performance and making deployments sluggish.
  • Hidden Security Risks: A vulnerability in a dependency three levels deep is just as dangerous as one you added yourself. The infamous Log4Shell incident was a perfect example of this exact blind spot.

Understanding Maven’s Resolution Strategy

The maven dependency tree command is your flashlight in the dark. It shows you exactly what Maven is doing behind the scenes. Originally introduced in 2008 with the Maven Dependency Plugin, it has become a non-negotiable tool for any serious Java developer.

While it started with simple text output, the plugin has evolved significantly. As of plugin version 3.7.0, it now supports advanced formats like DOT, GraphML, and JSON, with more improvements coming in every release. You can find the full history and feature set over on the official Apache Maven documentation.

One of its most crucial roles is revealing Maven’s “nearest-wins” resolution strategy. When Maven finds two different versions of the same library, it doesn’t automatically pick the newest one. Instead, it picks the one closest to your project in the dependency hierarchy.

This nearest-wins rule is a core Maven concept you have to understand. If your-project needs library-a (which uses common-lib-1.0) and library-b (which needs another-lib that uses common-lib-1.5), Maven will choose version 1.0. Why? Because it’s “nearer” to your project—only one level away.

This behavior often catches developers by surprise and can lead to some truly baffling bugs. The dependency:tree output makes it all transparent, showing you exactly which versions were chosen and which were (omitted for conflict). Learning to use this command isn’t just for debugging; it’s a fundamental skill for building stable and secure applications.

Alright, enough theory. Let’s get our hands dirty and run your first dependency tree analysis.

Running Your First Dependency Tree Analysis

A person types on a laptop displaying 'MVN Dependency: Tree' and a 'Run dependency Tree' prompt.

The great thing about the mvn dependency:tree command is that it just works. You don’t need any special setup or configuration. As long as you have a pom.xml file, you’re good to go.

Pop open your terminal, navigate to the root directory of your Maven project (the one with your main pom.xml), and fire off the command in its simplest form:

mvn dependency:tree

Maven will kick into gear, download the plugin if you don’t have it, and then print a clean, hierarchical tree right in your console. This is the ground truth—the definitive list of what’s really inside your project.

Interpreting the Default Output

At first glance, the output can feel a little overwhelming, but it’s actually quite logical. Let’s break down a typical example from a Spring Boot project that uses spring-boot-starter-web and Google’s guava library.

[INFO] com.example:my-app:jar:1.0.0 [INFO] +- org.springframework.boot:spring-boot-starter-web:jar:3.2.0:compile [INFO] | +- org.springframework.boot:spring-boot-starter-json:jar:3.2.0:compile [INFO] | | - com.fasterxml.jackson.core:jackson-databind:jar:2.15.3:compile [INFO] | +- org.springframework.boot:spring-boot-starter-tomcat:jar:3.2.0:compile [INFO] | | - org.apache.tomcat.embed:tomcat-embed-core:jar:10.1.16:compile [INFO] | - org.springframework:spring-webmvc:jar:6.1.1:compile [INFO] | - org.springframework:spring-context:jar:6.1.1:compile [INFO] +- com.google.guava:guava:jar:32.1.3-jre:compile [INFO] +- org.springframework.boot:spring-boot-starter-test:jar:3.2.0:test [INFO] | - org.junit.jupiter:junit-jupiter:jar:5.10.1:test [INFO] | - org.junit.platform:junit-platform-commons:jar:1.10.1:test

This simple text output reveals a ton of information. Here’s what to look for:

  • Direct Dependencies: Anything with a +- prefix is a library you explicitly added to your pom.xml. Here, it’s spring-boot-starter-web.
  • Transitive Dependencies: Lines starting with | or \ are the dependencies pulled in by your direct ones. You can see how jackson-databind gets included via spring-boot-starter-json.
  • Dependency Scope: The tag at the end of each line, like :compile or :test, is crucial. It tells you when that library is needed—for compiling your code, only for running tests, or just at runtime. Nailing down your scopes is fundamental to a clean development environment setup.

This simple text view is your first line of defense against dependency hell. By tracing which library brings in a specific transitive dependency, you gain the power to control your project’s classpath, size, and security posture. It makes the invisible visible.

Running this command should become muscle memory every time you add a new dependency or get a whiff of a version conflict. It builds the foundational understanding we’ll need for the more advanced filtering and conflict resolution techniques up next.

Advanced Filtering to Find What You Need

In any large, enterprise-level project, running the basic mvn dependency:tree command can be overwhelming. You’re often faced with hundreds, if not thousands, of lines. This is where the real power of the command shines: its ability to cut through the noise with filters.

Instead of staring at a firehose of information, you can get exactly what you need. This is all thanks to two powerful parameters: -Dincludes and -Dexcludes. Getting comfortable with these is what turns the dependency tree from a simple diagnostic tool into a precision instrument.

These parameters let you specify patterns to match against your dependencies. The format is groupId:artifactId:type:version, and you can use wildcards (*) for any part of it, which gives you a ton of flexibility.

Pinpointing Specific Libraries with Includes

Let’s say you just got a security alert for the Apache Commons Text library. You don’t need to see the entire tree—you just want to know which dependencies are pulling in commons-text. The -Dincludes parameter is perfect for this job.

You can run the command with a targeted filter:

mvn dependency:tree -Dincludes=org.apache.commons:commons-text

This completely changes the output. Instead of the full, sprawling tree, Maven now shows you only the paths that lead directly to the commons-text artifact. It prunes every other branch, giving you a clean view that answers your question immediately. It’s an incredibly efficient way to track down vulnerabilities.

You can get even more granular by combining filters with a comma. Want to see all your Jackson and Guava dependencies? Easy.

mvn dependency:tree -Dincludes=com.fasterxml.jackson.*:*,com.google.guava:guava

This saves a massive amount of time compared to digging through a giant text file by hand.

Cleaning Up the View with Excludes

On the flip side, sometimes the noise comes from dependencies you already know about and just don’t need to see. A classic example is anything with a test scope. While they’re essential for your build, they don’t get packaged into your final application and often just clutter up the tree.

The -Dexcludes parameter lets you hide them.

mvn dependency:tree -Dexcludes=*:*:*:test

This command tells Maven to ignore any dependency where the scope is test. The result is a much cleaner tree that only shows your application’s compile and runtime dependencies—in other words, what actually gets shipped.

The real magic happens when you combine these filters to perform highly specific queries. For instance, you could find all Spring Framework dependencies while simultaneously excluding the test-related ones by chaining the parameters together. This level of control is what separates basic usage from expert-level dependency wrangling.

For maximum precision, you can use both includes and excludes in a single command. Suppose you want to find everything pulling in log4j, but you need to ignore the log4j-over-slf4j bridge. Your command would look like this:

mvn dependency:tree -Dincludes=org.apache.logging.log4j:* -Dexcludes=*:log4j-over-slf4j

This combined approach lets you ask very complex questions about your project’s dependency graph. It’s an indispensable skill for preparing for a major library upgrade, hunting down a tricky version conflict, or just documenting a service’s third-party footprint.

Getting a Visual on Your Dependency Graph

Let’s be honest, the standard text output from mvn dependency:tree gets the job done, but it can be a real headache to parse in a complex project. Sometimes, a picture really is worth a thousand lines of console output.

A visual graph tells a much clearer story. This is especially true when you need to present your findings to the team or document the tangled web of a microservice’s architecture.

From Text to a Visual-Friendly File

Instead of just printing to the console, you can tell Maven to generate a file that visualization tools can actually understand. This is where you transform that abstract list of dependencies into a clear, navigable diagram.

To make this happen, you’ll use two key parameters with your command: -DoutputType and -DoutputFile. These flags tell Maven what format to export and where to save the file.

You have a few format options, but two are incredibly useful for building graphs:

  • DOT: A simple text language for describing graphs. It’s the perfect input for Graphviz, a fantastic open-source tool for graph visualization.
  • GraphML: An XML-based format designed specifically for graph structures. This one is great for more advanced analysis tools like Gephi.

So, to generate a DOT file that maps out your project’s entire dependency structure, you’d run this from your project’s root directory:

mvn dependency:tree -DoutputFile=dependencies.dot -DoutputType=dot

Check your project directory, and you’ll find a new file named dependencies.dot. This file holds everything needed to render a complete visual graph.

Creating the Graph with Graphviz

With your dependencies.dot file ready, the final step is using a tool like Graphviz to turn it into an image. If you have Graphviz installed, you can use its command-line tools to generate a PNG, SVG, or just about any other image format you need.

Here’s a common command to convert that DOT file into a PNG image:

dot -Tpng dependencies.dot -o dependencies.png

This command chews through the dependencies.dot file and spits out a visual representation saved as dependencies.png. You’ll get an image showing your project at the center, with lines branching out to every direct and transitive dependency. It makes the entire hierarchy incredibly easy to see at a glance.

This visual approach is a game-changer for presentations. Instead of forcing stakeholders to decipher a wall of text, you can show them a clean diagram that pinpoints exactly where a problematic library—like an outdated version of Jackson—is being pulled in from.

The ability to export data like this has come a long way. The command first showed up around late 2007, but it wasn’t until plugin version 3.7.0 in 2023 that modern output formats like JSON, DOT, and GraphML were officially added. You can dig into the command’s long history and see its latest features (like thread-safety for CI builds) by checking out the plugin’s official examples and documentation. This evolution makes it a seriously powerful tool for modern development workflows.

Solving Dependency Conflicts Like a Pro

This is where the maven dependency tree command really shines. Filtering and visualizing are useful, but its true power is revealed when you’re facing a build-breaking dependency conflict.

You’ve probably seen the tell-tale sign in your build logs: (omitted for conflict with...). This is Maven’s way of saying it found two different versions of a library and had to choose one. It uses a “nearest-wins” rule, but that doesn’t tell you why the conflict exists or what the impact is.

Uncovering the Full Story with Verbose Mode

To get to the bottom of it, you need more detail. The -Dverbose flag is the key. It forces the dependency tree to show you everything, including the versions that were omitted.

mvn dependency:tree -Dverbose

With the verbose output, you can see the full path for both the winning dependency and the one that was discarded. This lets you trace exactly which of your direct dependencies are pulling in the competing versions. No more guesswork.

A classic headache is when two libraries require incompatible versions of Jackson. Maybe Library A needs jackson-databind:2.14.0, but Library B brings in jackson-databind:2.15.3. The verbose tree immediately shows you both paths, pointing directly to the source of the problem.

Sometimes, a visual representation makes these complex relationships easier to untangle. You can turn the text output from your terminal into a much clearer graph.

A flowchart titled 'Visualizing Dependencies' showing a process from Terminal to Data File to Graph.

This simple flow shows how raw command-line data can be transformed into something you can actually act on.

Actionable Strategies for Conflict Resolution

Once you know where the conflict is coming from, you have a couple of solid ways to fix it.

1. Enforcing a Version with Dependency Management

The best practice is to take control yourself. Use the <dependencyManagement> section of your pom.xml to declare the official version for your project.

This tells Maven, “No matter what my transitive dependencies ask for, always use this specific version.”

By centralizing version control in <dependencyManagement>, you create a single source of truth. This not only resolves the immediate conflict but also prevents future ones, making your build more predictable and stable.

This approach is incredibly valuable in multi-module projects, where it guarantees consistency and prevents different modules from pulling in conflicting versions.

2. Excluding a Transitive Dependency

What if you don’t want the conflicting dependency at all? Maybe a library is pulling in an old, vulnerable version of a utility you don’t even use. Here, you can use an <exclusion> tag directly inside your dependency declaration.

This is a more surgical fix. It tells Maven to bring in the main library but to completely ignore one of its transitive dependencies. It’s perfect for cutting out bloat or removing a library that’s causing trouble.

This tactic is a fundamental part of maintaining a clean, healthy project. As you streamline your build process, you may find yourself looking for other ways to improve your development lifecycle. For a deeper dive, check out our guide on continuous integration best practices.

Common Questions About the Maven Dependency Tree

Even when you’ve got the basics down, a few questions always seem to pop up during daily development. Here are some quick answers to the problems developers hit most often when wrangling the maven dependency tree command.

How Can I See Why a Dependency Was Omitted?

When Maven silently drops a dependency version you were expecting, the key is the -Dverbose flag. Honestly, it’s the most critical parameter you have for debugging conflicts.

Running mvn dependency:tree -Dverbose tells Maven to show you its work. The output expands to include every version it considered but ultimately ignored. You’ll get explicit messages like (omitted for conflict with 1.2.3), which lays out the entire decision-making process so you can see exactly why a certain version won.

What Is the Difference Between dependency:tree and dependency:analyze?

While they both poke around your project’s dependencies, they’re built for completely different jobs.

  • dependency:tree is all about visualizing the hierarchy. It shows you the full, nested relationship of every library—both the ones you added and the transitive ones they pulled in. Its purpose is to map out the entire dependency graph.
  • dependency:analyze is more like a linter for your pom.xml. It’s designed to spot mismatches, like declared dependencies your code never actually uses, or, conversely, libraries your code uses that you forgot to declare.

Think of it this way: dependency:tree helps you hunt down and fix version conflicts. dependency:analyze helps you tidy up your project by getting rid of unused “dead weight” libraries. They’re two sides of the same coin for good project hygiene.

Can I Use This Command in My CI/CD Pipeline?

Absolutely. In fact, you should. Automating dependency analysis is a fantastic practice for keeping your builds stable and predictable. A common move is to run the command and just pipe the output to a file.

mvn dependency:tree -DoutputFile=dependencies.log

This saves the entire tree to dependencies.log. You can then archive this file as a build artifact in Jenkins, GitLab CI, or whatever CI system you’re using for later inspection.

For a more hands-on approach, many teams use the Maven Enforcer Plugin. You can configure its dependencyConvergence rule to automatically fail the build if it finds any version conflicts. This ensures no clashing dependencies ever sneak into a release.


Ready to stop bugs before they hit production? GoReplay lets you capture and replay real user traffic in your test environments, ensuring every update is rock-solid. Learn more and start testing with confidence at https://goreplay.org.

Ready to Get Started?

Join these successful companies in using GoReplay to improve your testing and deployment processes.