
Maven Build Lifecycle: Phases and Goals Explained
Maven’s build lifecycle is one of those things you’ll stumble across constantly as a Java developer, but many folks never dig deeper than running “mvn clean install” and calling it a day. Understanding how Maven’s lifecycle phases work under the hood can save you hours of debugging weird build issues and help you optimize your deployment pipelines. This deep dive will walk you through the three built-in lifecycles, break down the key phases you actually use, explain how goals fit into the picture, and show you practical examples of customizing builds for different environments.
How Maven Build Lifecycle Works
Maven operates on three built-in build lifecycles that run independently: default (handles project deployment), clean (cleans up artifacts), and site (generates project documentation). Each lifecycle consists of phases that execute in a specific order, and each phase can have multiple goals bound to it.
When you run a Maven command, you’re essentially telling it to execute all phases up to and including the one you specified. So when you run mvn test
, Maven doesn’t just run tests – it also executes validate, compile, and test-compile phases first.
Here’s how the three lifecycles break down:
Lifecycle | Purpose | Common Phases |
---|---|---|
Default | Main build process | compile, test, package, install, deploy |
Clean | Cleanup build artifacts | pre-clean, clean, post-clean |
Site | Documentation generation | pre-site, site, post-site, site-deploy |
The key thing to understand is that phases are just containers – they don’t do anything by themselves. The actual work happens through goals, which are specific tasks provided by Maven plugins. Goals get bound to phases either by default (based on your project’s packaging type) or through explicit configuration in your pom.xml.
Step-by-Step Implementation Guide
Let’s walk through setting up a practical Maven project and customizing its build lifecycle. We’ll create a web application that demonstrates different lifecycle phases in action.
Step 1: Create a basic Maven web project
mvn archetype:generate -DgroupId=com.example.webapp \
-DartifactId=lifecycle-demo \
-DarchetypeArtifactId=maven-archetype-webapp \
-DinteractiveMode=false
cd lifecycle-demo
Step 2: Examine the default phase-to-goal mappings
Run this command to see what goals are bound to each phase for your project:
mvn help:describe -Dcmd=compile
You’ll see output showing which plugin goals execute during the compile phase. For a web application, it typically includes:
[INFO] 'compile' is a phase corresponding to this plugin:
org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile
Step 3: Add custom goal bindings
Here’s a practical example of customizing your build lifecycle. Add this to your pom.xml to run additional tasks during different phases:
<build>
<plugins>
<!-- Run integration tests during verify phase -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>3.0.0-M7</version>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- Copy resources during prepare-package phase -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>3.2.0</version>
<executions>
<execution>
<id>copy-config</id>
<phase>prepare-package</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/config</outputDirectory>
<resources>
<resource>
<directory>src/main/config</directory>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
Step 4: Test your lifecycle customizations
Run Maven with the debug flag to see exactly what’s happening:
mvn clean package -X
This will show you detailed output of which goals execute during each phase, helping you understand the flow and debug any issues.
Real-World Examples and Use Cases
Here are some practical scenarios where understanding Maven lifecycle phases becomes crucial:
Database Migration During Build
You can bind database migration tools like Flyway to run during specific phases:
<plugin>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-maven-plugin</artifactId>
<version>8.5.13</version>
<executions>
<execution>
<phase>pre-integration-test</phase>
<goals>
<goal>migrate</goal>
</goals>
</execution>
</executions>
<configuration>
<url>jdbc:h2:file:./target/testdb</url>
<user>sa</user>
</configuration>
</plugin>
Docker Image Building
When deploying to containerized environments, you might want to build Docker images during the package phase:
<plugin>
<groupId>com.spotify</groupId>
<artifactId>dockerfile-maven-plugin</artifactId>
<version>1.4.13</version>
<executions>
<execution>
<id>default</id>
<phase>package</phase>
<goals>
<goal>build</goal>
</goals>
</execution>
</executions>
<configuration>
<repository>${project.artifactId}</repository>
<tag>${project.version}</tag>
</configuration>
</plugin>
Multi-Environment Configuration
You can use Maven profiles to bind different goals based on your target environment:
<profiles>
<profile>
<id>production</id>
<build>
<plugins>
<plugin>
<groupId>com.github.eirslett</groupId>
<artifactId>frontend-maven-plugin</artifactId>
<version>1.12.1</version>
<executions>
<execution>
<phase>generate-resources</phase>
<goals>
<goal>npm</goal>
</goals>
<configuration>
<arguments>run build:prod</arguments>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
Comparison with Alternative Build Tools
Understanding how Maven’s lifecycle compares to other build tools helps put its approach in perspective:
Tool | Build Model | Flexibility | Learning Curve |
---|---|---|---|
Maven | Declarative lifecycle phases | Medium – convention over configuration | Medium |
Gradle | Task-based DAG | High – fully programmable | High |
Ant | Imperative XML targets | High – complete control | Low |
SBT | Task-based with scopes | High – Scala-based DSL | High |
Maven’s lifecycle approach shines when you have standard Java projects that follow conventional patterns. The predefined phases make it easy to understand what’s happening and when. However, if you need complex custom build logic, Gradle’s task-based approach might be more suitable.
Performance-wise, Maven’s lifecycle can be slower than Gradle for large projects because it doesn’t have built-in incremental compilation and parallel execution is limited. Here’s a rough comparison for a typical Spring Boot project:
- Maven clean install: ~45 seconds
- Gradle clean build: ~32 seconds
- Gradle build (incremental): ~8 seconds
Best Practices and Common Pitfalls
Best Practices:
- Use the right phase for custom goals: Don’t bind resource copying to the compile phase – use prepare-package or process-resources instead
- Keep plugin versions explicit: Always specify plugin versions in your pom.xml to ensure reproducible builds
- Use profiles for environment-specific builds: Don’t hardcode environment settings in your main build configuration
- Leverage parallel builds: Use
mvn -T 4 clean install
to run with 4 threads on multi-module projects - Skip unnecessary phases in CI: Use
-DskipTests
or-Dmaven.test.skip=true
when appropriate
Common Pitfalls to Avoid:
- Binding goals to wrong phases: Don’t put integration tests in the test phase – they belong in integration-test or verify
- Not understanding phase execution order: Remember that running
mvn verify
will also run compile, test, and package phases - Overcomplicating with custom lifecycles: Stick to the default lifecycle unless you have a very specific need
- Ignoring plugin goal defaults: Check what goals are already bound to phases before adding your own
Troubleshooting Common Issues:
If your build is failing mysteriously, use these debugging commands:
# See effective POM with all plugin bindings
mvn help:effective-pom
# Debug plugin execution
mvn -X clean compile
# See dependency tree
mvn dependency:tree
# Analyze plugin goals bound to phases
mvn fr.jcgay.maven.plugins:buildplan-maven-plugin:list
For deployment scenarios, especially when using VPS or dedicated servers, you’ll often want to create deployment-specific profiles that handle different packaging requirements, database configurations, and resource optimization.
One interesting advanced technique is creating custom lifecycle phases using the Maven lifecycle extension mechanism. This is rarely needed, but can be useful for specialized build processes in enterprise environments.
The official Maven Lifecycle Guide provides comprehensive documentation on all built-in phases and their default goal bindings. For plugin development, the Plugin Developers Guide explains how to create custom goals that integrate with Maven’s lifecycle system.

This article incorporates information and material from various online sources. We acknowledge and appreciate the work of all original authors, publishers, and websites. While every effort has been made to appropriately credit the source material, any unintentional oversight or omission does not constitute a copyright infringement. All trademarks, logos, and images mentioned are the property of their respective owners. If you believe that any content used in this article infringes upon your copyright, please contact us immediately for review and prompt action.
This article is intended for informational and educational purposes only and does not infringe on the rights of the copyright owners. If any copyrighted material has been used without proper credit or in violation of copyright laws, it is unintentional and we will rectify it promptly upon notification. Please note that the republishing, redistribution, or reproduction of part or all of the contents in any form is prohibited without express written permission from the author and website owner. For permissions or further inquiries, please contact us.