Skip to content

Maven — POM.xml, Build Lifecycle, Dependencies, Plugins, and Multi-Module Projects

DodaTech Updated 2026-06-28 5 min read

In this tutorial, you will learn about Maven. We cover key concepts, practical examples, and best practices to help you master this topic.

Apache Maven is a build automation and project management tool that uses a Project Object Model (POM) for configuration. Unlike Ant (which required writing imperative build scripts), Maven is convention-based — it defines standard phases and plugins, so most builds require minimal configuration beyond listing dependencies.

What You'll Learn

  • pom.xml structure and core elements
  • The build lifecycle: phases and goals
  • Dependency management: scope, exclusions, versioning
  • Plugins for compilation, testing, and packaging
  • Multi-module projects

Why It Matters

Maven is the de facto standard for Java builds. Understanding Maven is essential for contributing to open-source projects, working in enterprise environments, and managing dependencies without version conflicts.

Real-World Use

Every Spring Boot project, every library on Maven Central, and virtually every Java CI/CD pipeline uses Maven or Gradle.


pom.xml Structure

<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
         http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.example</groupId>
    <artifactId>my-app</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>My Application</name>
    <description>A sample Java application</description>
</project>

Coordinates

  • groupId — reversed domain name (com.example, org.apache)
  • artifactId — project name (spring-boot-starter-web)
  • version — release number (1.0.0, 2.5.0-SNAPSHOT)
  • packaging — jar, war, pom, ear

The Build Lifecycle

Maven has three built-in lifecycles: default, clean, site. The default lifecycle phases:

Phase Description
validate Validate project structure
compile Compile source code
test Run unit tests
package Build JAR/WAR
verify Run integration tests
install Copy artifact to local Repository
deploy Copy artifact to remote repository
mvn compile          # compile only
mvn test             # compile + test
mvn package          # compile + test + package
mvn install          # full build + copy to local repo
mvn clean install    # clean + full build

Dependency Management

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <version>3.2.0</version>
    </dependency>
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter</artifactId>
        <version>5.10.0</version>
        <scope>test</scope>
    </dependency>
</dependencies>

Scopes

Scope Description
compile Default — available everywhere
provided Available at compile time, provided by runtime (e.g., Servlet API)
runtime Not needed at compile time, needed at runtime
test Available only for test compilation and execution
system Similar to provided, but must include the JAR path

Transitive Dependencies

Maven automatically includes dependencies of your dependencies. Use mvn dependency:tree to visualize:

mvn dependency:tree

Excluding Transitive Dependencies

<dependency>
    <groupId>com.example</groupId>
    <artifactId>library-a</artifactId>
    <version>1.0</version>
    <exclusions>
        <exclusion>
            <groupId>com.example</groupId>
            <artifactId>library-b</artifactId>
        </exclusion>
    </exclusions>
</dependency>

Plugins

Plugins add goals to lifecycle phases:

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.11.0</version>
            <configuration>
                <source>21</source>
                <target>21</target>
            </configuration>
        </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-surefire-plugin</artifactId>
            <version>3.1.0</version>
        </plugin>
    </plugins>
</build>

Common Plugins

  • maven-compiler-plugin — compile with specific Java version
  • maven-surefire-plugin — run unit tests
  • maven-failsafe-plugin — run integration tests
  • maven-jar-plugin — create JAR with manifest
  • maven-shade-plugin — create uber JAR with dependencies

Multi-Module Projects

Parent POM (pom.xml with packaging=pom):

<project>
    <groupId>com.example</groupId>
    <artifactId>my-project</artifactId>
    <version>1.0.0</version>
    <packaging>pom</packaging>

    <modules>
        <module>core</module>
        <module>api</module>
        <module>web</module>
    </modules>
</project>

Child module (core/pom.xml):

<project>
    <parent>
        <groupId>com.example</groupId>
        <artifactId>my-project</artifactId>
        <version>1.0.0</version>
    </parent>

    <artifactId>core</artifactId>
</project>

Dependency Management in Parent

<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>

Common Mistakes

  1. Not specifying Java version. The maven-compiler-plugin defaults to Java 5 or 8 depending on the version. Always set <source> and <target>.
  2. Committing IDE files. Use .gitignore to exclude target/, .idea/, and *.iml files.
  3. Forgetting dependency scope. Test libraries (JUnit, Mockito) should have <scope>test</scope> to avoid shipping them in production.
  4. Version conflicts. Use mvn dependency:tree to debug conflicts. Use <dependencyManagement> in parent POM to centralize versions.
  5. Slow builds without parallel mode. Use mvn -T 4 to compile modules in parallel.

Practice Questions

1. What is the default lifecycle phase if you run mvn without arguments?
mvn runs the default lifecycle up to the package phase (including compile, test, package).

2. What is the difference between test and provided scope?
test is available only during test compilation and execution. provided is available during compile but not packaged — the runtime environment provides it.

3. How do you exclude a transitive dependency?
Using <exclusions> in the dependency declaration.

4. What is the purpose of the dependencyManagement section?
It centralizes dependency versions for a multi-module project. Child modules can declare dependencies without specifying the version.

5. What does mvn dependency:tree do?
It prints the dependency tree, showing transitive dependencies and helping debug conflicts.

Challenge Question:
Create a multi-module Maven project with parent, core, and app modules. The core module depends on Apache Commons Lang3. The app module depends on core. Use dependencyManagement in the parent to manage versions. Add the maven-compiler-plugin with Java 21. Build, test, and package the application.

FAQ

What is the difference between Maven and Gradle?

Maven uses XML and follows a strict lifecycle model. Gradle uses a Groovy/Kotlin DSL and is more flexible and faster (incremental builds). Maven is still more widely used for enterprise projects.

What is Maven Central?

The default remote repository for Maven dependencies. It hosts millions of open-source libraries. You can also use JCenter, Google's Maven repo, or your own private repository.

What is a SNAPSHOT version?

A version ending with -SNAPSHOT (e.g., 1.0.0-SNAPSHOT) indicates a development version. Maven checks for updates more frequently. Release versions are cached forever once downloaded.

What is the local repository?

A directory on your machine (default: ~/.m2/repository) where Maven caches downloaded artifacts. No internet access is needed for previously downloaded dependencies.

How do I skip tests?

mvn install -DskipTests skips test compilation. mvn install -Dmaven.test.skip=true skips both compilation and execution.

Mini Project

Create a complete Maven project structure:

  1. Run mvn archetype:generate or manually create the directory structure
  2. Add dependencies for JUnit 5 and Apache Commons Lang3
  3. Write a simple utility class (StringUtils.reverse(String)) and a unit test
  4. Configure the maven-compiler-plugin for Java 21
  5. Build with mvn clean package
  6. Run the JAR: java -jar target/my-app-1.0.0.jar
  7. Examine the dependency tree with mvn dependency:tree

What's Next

Maven is a powerful build tool, but Gradle offers a different approach with its Groovy/Kotlin DSL and incremental build system. Lesson 46 covers Gradle — build.gradle, Kotlin DSL, tasks, dependencies, and the Gradle wrapper.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro