Skip to content

Apache Maven Build Guide — Complete Java Project Automation

DodaTech Updated 2026-06-23 6 min read

In this tutorial, you'll learn about Apache Maven Build Guide. We cover key concepts, practical examples, and best practices to help you understand and apply this topic effectively.

Apache Maven is a build automation tool for Java projects that manages dependencies, compiles source code, runs tests, and packages artifacts using declarative XML configuration and a convention-over-configuration philosophy.

What You'll Learn

You'll learn how to configure a Maven POM file, manage dependencies with transitive resolution, execute build lifecycle phases, create multi-module projects, and integrate plugins for testing, packaging, and reporting.

Why Maven Matters

Every Java project needs a build system. Maven enforces a standard project structure and dependency management model that works across thousands of real-world projects. Understanding Maven is essential for Java development, CI/CD pipelines, and enterprise application deployment.

Real-World Use

Maven builds everything from small libraries to the backend services powering Doda Browser — where multi-module Maven projects manage shared libraries, API contracts, and deployable services with consistent versioning across the team.

Prerequisites

  • Java 11+ installed
  • Basic YAML or XML familiarity
  • Maven 3.9+ installed

Step 1: Project Setup and POM Structure

Every Maven project starts with a pom.xml file. This file declares the project coordinates, dependencies, and build configuration.

<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.dodatech</groupId>
    <artifactId>hello-maven</artifactId>
    <version>1.0.0</version>
    <packaging>jar</packaging>

    <properties>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
            <version>2.10.1</version>
        </dependency>
    </dependencies>
</project>

Expected result: Maven reads this POM, downloads the Gson dependency from Maven Central, and makes it available during compilation.

Step 2: Build Lifecycle and Phases

Maven defines a standard build lifecycle with phases that execute in order. The three main lifecycles are default, clean, and site.

# Compile source code
mvn compile

# Run all tests
mvn test

# Package into JAR
mvn package

# Install into local repository
mvn install

# Full clean build
mvn clean install

# Skip tests during build
mvn package -DskipTests

Expected output: Running mvn clean install produces output showing each phase — resources, compile, test, package, install — with BUILD SUCCESS at the end.

Step 3: Dependency Management

Maven resolves transitive dependencies automatically. If your project depends on Library A, and Library A depends on Library B, Maven downloads both. You can exclude unwanted transitive dependencies using exclusions.

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

<!-- Scope controls when the dependency is available -->
<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter-api</artifactId>
    <version>5.10.0</version>
    <scope>test</scope>
</dependency>

Expected behavior: Dependencies with scope=test are only available during the test phase and are excluded from the final JAR. Exclusions prevent unwanted transitive libraries from being pulled in.

Step 4: Plugins and Reporting

Maven plugins extend the build lifecycle. The Surefire plugin runs tests, the JAR plugin packages artifacts, and the Shade plugin creates fat JARs with all dependencies bundled.

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-surefire-plugin</artifactId>
            <version>3.2.0</version>
            <configuration>
                <includes>
                    <include>**/*Test.java</include>
                </includes>
                <reportNameSuffix>unit-tests</reportNameSuffix>
            </configuration>
        </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-shade-plugin</artifactId>
            <version>3.5.0</version>
            <executions>
                <execution>
                    <phase>package</phase>
                    <goals><goal>shade</goal></goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

Expected behavior: With the Shade plugin, mvn package produces a fat JAR containing your classes plus all runtime dependencies. The Surefire plugin generates an XML test report in target/surefire-reports/.

Step 5: Multi-Module Projects

Real projects split into multiple modules — a shared library, an API module, and a web application. The parent POM lists child modules, and each child inherits common configuration.

<!-- Parent pom.xml -->
<project>
    <groupId>com.dodatech</groupId>
    <artifactId>myapp-parent</artifactId>
    <version>1.0.0</version>
    <packaging>pom</packaging>

    <modules>
        <module>core</module>
        <module>api</module>
        <module>webapp</module>
    </modules>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>com.dodatech</groupId>
                <artifactId>core</artifactId>
                <version>1.0.0</version>
            </dependency>
        </dependencies>
    </dependencyManagement>
</project>
<!-- core/pom.xml — inherits from parent -->
<project>
    <parent>
        <groupId>com.dodatech</groupId>
        <artifactId>myapp-parent</artifactId>
        <version>1.0.0</version>
    </parent>
    <artifactId>core</artifactId>
</project>

Expected behavior: Running mvn install from the parent directory builds all modules in reactor order, resolving inter-module dependencies automatically.

Architecture

flowchart LR
    subgraph "Maven Build"
        POM[pom.xml]
        SRC[src/ Directory]
        TARGET[target/ Directory]
    end
    subgraph "Lifecycle Phases"
        COMPILE[compile] --> TEST[test]
        TEST --> PACKAGE[package]
        PACKAGE --> INSTALL[install]
        INSTALL --> DEPLOY[deploy]
    end
    subgraph "External"
        CENTRAL[Maven Central]
        LOCAL[~/.m2/Repository]
    end
    POM --> COMPILE
    SRC --> COMPILE
    COMPILE --> TARGET
    CENTRAL -->|download deps| LOCAL
    LOCAL --> COMPILE

Common Errors

1. Plugin execution not covered by lifecycle configuration Maven requires plugin executions to be bound to lifecycle phases. If a plugin goal is not bound to any phase, it won't run. Always specify the <phase> element.

2. Jar hell from conflicting transitive versions Two dependencies may pull different versions of the same library. Use mvn dependency:tree to visualize the conflict, then add an exclusion or manage the version in dependencyManagement.

3. Non-resolvable parent POM If a child module's parent POM is not in the local Repository or Maven Central, the build fails. Always run mvn install on the parent first, or use <relativePath> to point to the parent's POM file.

4. Build fails with missing artifact A dependency might exist but not be reachable due to Repository configuration. Add the required Repository in the POM's <repositories> section.

5. Tests fail with NoClassDefFoundError A test dependency is missing or has the wrong scope. JUnit and test frameworks should use <scope>test</scope>.

Practice Questions

1. What is the purpose of the element in a POM? It defines the artifact type produced by the build — jar, war, pom, or ear. A parent POM uses pom packaging. This affects which lifecycle phases and plugins are relevant.

2. How does Maven resolve transitive dependencies? Maven reads the dependency tree recursively. Each dependency's POM lists its own dependencies, and Maven downloads them all, merging versions using a nearest-wins Strategy.

3. What is the difference between mvn package and mvn install? mvn package produces the artifact in the target/ directory. mvn install does the same plus copies the artifact into the local Maven Repository (~/.m2/Repository) so other local projects can depend on it.

4. Challenge: Create a multi-module project Build a parent POM with three modules — utils, service, and app. The service module depends on utils, and app depends on service. Verify that building from the parent compiles all three in the correct order.

5. Challenge: Custom archetype Create a Maven archetype that generates a new project with preconfigured dependencies for logging, testing, and JSON Parsing.

FAQ

How is Maven different from Gradle?

Maven uses XML for configuration and follows a rigid lifecycle model. Gradle uses Groovy or Kotlin DSL and is more flexible with incremental builds. Maven is more predictable; Gradle is faster for large projects.

Can Maven build non-Java projects?

Maven is designed for Java but can build other JVM languages like Kotlin and Scala through plugins. It is not typically used for native or frontend projects.

What is the local Repository and where is it stored?

The local Repository at ~/.m2/Repository caches all downloaded dependencies. Maven checks here first before fetching from remote repositories. Clearing it forces a fresh download.

Next Steps

  • Explore Gradle for an alternative build tool with Groovy DSL
  • Learn how CI/CD pipelines integrate Maven builds with Jenkins or GitHub Actions
  • Automate dependency updates with the Maven Versions plugin
  • Try the Docker build strategies tutorial for containerizing Maven artifacts

Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro