• Home
  • Docker
  • Kubernetes
  • LLMs
  • Java
  • Ubuntu
  • Maven
  • Big Data
  • Archived
Maven | Project Dependencies
  1. Repositories
  2. Direct Dependencies
  3. Transitive Dependencies
  4. Resolve Transitive Dependencies Conflicts

  1. Repositories
    All dependencies (artifacts and plugins) defined in the pom file of the project are downloaded from remote repositories and saved in a local repository on disk. The remote repositories can be defined in the pom file or in the settings.xml file.

    To add repositories in the settings.xml file, you can do the folowing:

    If some cases, you might want to add manually an artifact to your local repository "${HOME}/.m2/repository". To do so, you can use the command mvn install:install-file:
  2. Direct Dependencies
    There are three important phases that might be required to build a Maven project:
    • First, the compilation of the source code: this phase is referred to as "compile".
    • Second, the compilation of the test source code: this phase is referred to as "test-compile".
    • Third, the packaging of the project: this phase is referred to as "package".

    Notes:
    • When the command "mvn compile" is run, only the first phase ("compile") will be executed.
    • When the command "mvn test-compile" is run, the phases "compile" and "test-compile" will be executed.
    • And when the command "mvn package" is run, the phases "compile", "test-compile", and "package" will be executed.

    We will focus on these three phases to explain how Maven resolves project dependencies.
    See this introduction about Maven build phases: http://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html

    So how does a project dependency affect the build of a project?

    When a dependency is added to the "pom.xml" file, its scope is specified.
    Here's an example of a dependency (the project depends on "junit" to execute test code):

    Before Maven starts building a project, Maven will try to resolve all project dependencies.
    For each of the phases "compile", "test-compile", and "package" Maven will decide if a dependency is needed to successfully execute each phase.
    The scope of each dependency will let Maven decide if it is needed to execute a specific phase.

    Here are the four main scopes of a dependency:

    • compile (this is the default scope if you don't specify a scope for the dependency in the pom file):
      Dependencies that have the scope "compile" will be needed to successfully execute all the three phases: compile the code, compile the test code, and package the project.
      Dependencies with the scope "compile" will be available to be packaged with the artifact of the project.
      Dependencies with the scope "compile" are transitive.

    • test
      Dependencies that have the scope "test" will be needed to successfully execute the phase "test-compile": compile the test code.
      Dependencies with the scope "test" will not be packaged with the artifact of the project.
      Dependencies with the scope "test" are not transitive.

    • provided
      Dependencies that have the scope "provided" will be needed to successfully execute the phases "compile" and "test-compile": compile the code and compile the test code.
      Dependencies with the scope "provided" will not be packaged with the artifact of the project.
      Dependencies with the scope "provided" are not transitive.

    • runtime
      Dependencies that have the scope "runtime" will be needed to successfully execute the phases "test-compile" and "package": compile the test code and package the project.
      Dependencies with the scope "runtime" will be available to be packaged with the artifact of the project.
      Dependencies with the scope "runtime" are transitive.

    There are also the scobe "system" and "import". See this page for more details: https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html#Dependency_Scope

    Note that Maven provide options to skip compiling, building, and/or executing the test code.
    The parameter "-Dmaven.test.skip=true" will skip compiling, building, and executing the test code.
    The parameter "-DskipTests" will compile and build the test code but will skip executing the test code.

    The parameter "-Dmaven.main.skip=true" will skip compiling, building, and executing the source code.
    Note that adding this parameter, might fail compiling the test code, in case it depends on the source code.

    Here's a table that summarize the relationship between the dependency scope and the build phases.
    Let's say a project "A" depends on project "B".
    Scope
    Direct Dependency
    ("A" ► "B")
    Related Phases Comment
    compile "compile"
    "test-compile"
    "package"
    If any of the phases "compile", "test-compile", or "package" has to be executed for the project "A", the build will fail if Maven cannot find the dependency "B" in the repository.
    test "test-compile" If the phase "test-compile" has to be executed for the project "A", the build will fail if Maven cannot find the dependency "B" in the repository.

    Note that if the phase "compile" has to be executed for the project "A", the build will fail if the code (not test code) of the project "A" refers the code of the project "B".
    provided "compile"
    "test-compile"
    If any of the phases "compile" or "test-compile" has to be executed for the project "A", the build will fail if Maven cannot find the dependency "B" in the repository.
    runtime "test-compile"
    "package"
    If any of the phases "test-compile" or "package" has to be executed for the project "A", the build will fail if Maven cannot find the dependency "B" in the repository.

    Note that if the phase "compile" has to be executed for the project "A", the build will fail if the code (not test code) of the project "A" refers the code of the project "B".
  3. Transitive Dependencies
    A transitive dependency defines the relationship between two projects that are not linked together by a direct dependency.
    For example:
    Let's say project "A" has a direct dependency on project "B" and project "B" has a direct dependency on project "C".
    Assuming that project "A" has no direct dependency on project "C", then project "A" has a transitive dependency on project "C".

    In other words: if "A" depends on "B" ("A" ► "B") and "B" depends on "C" ("B" ► "C") then "A" depends on "C" ("A" ► "C").

    That's said, we need to know when and how Maven resolve transitive dependencies.
    The scope of the direct and transitive dependencies will let Maven decide if they are needed to successfully execute a specific phase.

    For the following, let's suppose that project "A" depends on project "B" and project "B" depends on project "C".
    We assume that project "A" has no direct dependency on project "C".
    Then, project "A" might have a transitive dependency on project "C".

    First we need to define the scope of the direct dependency of project "A" on project "B".
    And second we need to define the scope of the direct dependency of project "B" on project "C".
    Then we can resolve the scope of the transitive dependency of project "A" on project "C".

    Once the scope of the transitive dependency is known, Maven will use the same rules to decide if the project referred by the transitive dependency is needed to successfully execute a build phase.

    There are two scenarios:

    • compile
      If the scope of the direct dependency of "B" on "C" is "compile", then the scope of the transitive dependency of "A" on "C" is the same scope as the direct dependency of "A" on "B".

    • runtime
      If the scope of the direct dependency of "B" on "C" is "runtime", then the scope of the transitive dependency of "A" on "C" is the same scope as the direct dependency of "A" on "B". Except the case where the scope of the direct dependency of "A" on "B" is "compile", then the scope of the transitive dependency of "A" on "C" is "runtime".

    Note that if the scope of the direct dependency of "B" on "C" is "provided" or "test", then "C" is not visible for "A". Maven will throw an error if the code (including test code) of "A" refers the code of "C".

    Here's a table that summarizes the case when the scope of the direct dependency of "B" on "C" is "compile":

    Scope
    Direct Dependency
    ("B" ► "C")
    Scope
    Direct Dependency
    ("A" ► "B")
    Scope
    Transitive Dependency
    ("A" ► "C")
    Related Phases Comment
    compile compile compile "compile"
    "test-compile"
    "package"
    If any of the phases "compile", "test-compile", or "package" has to be executed for the project "A", the build will fail if Maven cannot find the dependency "C" in the repository.
    compile test test "test-compile" If the phase "test-compile" has to be executed for the project "A", the build will fail if Maven cannot find the dependency "C" in the repository.

    Note that if the phase "compile" has to be executed for the project "A", the build will fail if the code (not test code) of the project "A" refers the code of the project "C".
    compile provided provided "compile"
    "test-compile"
    If any of the phases "compile" or "test-compile" has to be executed for the project "A", the build will fail if Maven cannot find the dependency "C" in the repository.
    compile runtime runtime "test-compile"
    "package"
    If any of the phases "test-compile" or "package" has to be executed for the project "A", the build will fail if Maven cannot find the dependency "C" in the repository.

    Note that if the phase "compile" has to be executed for the project "A", the build will fail if the code (not test code) of the project "A" refers the code of the project "C".

    Here's a table that summarize the case when the scope of the direct dependency of "B" on "C" is "runtime":

    Scope
    Direct Dependency
    ("B" ► "C")
    Scope
    Direct Dependency
    ("A" ► "B")
    Scope
    Transitive Dependency
    ("A" ► "C")
    Related Phases Comment
    runtime compile runtime "test-compile"
    "package"
    If any of the phases "test-compile" or "package" has to be executed for the project "A", the build will fail if Maven cannot find the dependency "C" in the repository.

    Note that if the phase "compile" has to be executed for the project "A", the build will fail if the code (not test code) of the project "A" refers the code of the project "C".
    runtime test test "test-compile" If the phase "test-compile" has to be executed for the project "A", the build will fail if Maven cannot find the dependency "C" in the repository.

    Note that if the phase "compile" has to be executed for the project "A", the build will fail if the code (not test code) of the project "A" refers the code of the project "C".
    runtime provided provided "compile"
    "test-compile"
    If any of the phases "compile" or "test-compile" has to be executed for the project "A", the build will fail if Maven cannot find the dependency "C" in the repository.
    runtime runtime runtime "test-compile"
    "package"
    If any of the phases "test-compile" or "package" has to be executed for the project "A", the build will fail if Maven cannot find the dependency "C" in the repository.

    Note that if the phase "compile" has to be executed for the project "A", the build will fail if the code (not test code) of the project "A" refers the code of the project "C".
  4. Resolve Transitive Dependencies Conflicts
    Transitive dependencies might bring different version of the same artifacts. Maven needs to pick only one version of the artifacts for your project. The closest version (regardless if it's the newest or not) in the dependencies tree will be chosen. If there are multiple version on the same level of three, then Maven will choose the first one found.

    In many cases, the version chosen by Maven might not be the right one for your project. To address this issue, you need to add the artifact as a dependency to the pom file of your project and specify the version you want to use.

    In some cases you might want to exclude a transitive dependency so it (and all its direct and transitive dependencies) won't be resolved by Maven:

    You can use the Maven Dependency Plugin to print the dependency tree of your project:

© 2025  mtitek