Definition
- Maven default lifecycle -- a fixed ordered sequence of phases where invoking any phase executes all phases before it.
- validate -- checks that the project is correct and all necessary information is available.
- compile -- compiles main source code into target/classes.
- test -- runs unit tests; if they fail, the build stops.
- package -- bundles compiled code into a distributable format (JAR, WAR).
- verify -- runs integration tests and quality checks.
- install -- copies the artifact into the local .m2 repository on your machine.
- deploy -- uploads the artifact to a remote shared repository (Nexus, Artifactory) configured by distributionManagement.
Think of baking a cake for National Bank of India branches. The lifecycle is the fixed recipe: check ingredients (validate), mix (compile), taste-test (test), box it (package), final quality inspection (verify), then distribute. mvn install is putting the finished cake in your own kitchen fridge so only your household can eat it -- local and private. mvn deploy is sending the cake to the central bakery warehouse so every branch in the country can collect it -- shared and organizational. The distributionManagement section is the warehouse address and delivery pass.
Understanding the Concepts
What are the lifecycle phases in order?
The Maven default lifecycle is a fixed, ordered chain. The golden rule is that invoking a phase runs that phase and all phases before it. Here are the main phases in order: validate, compile, test, package, verify, install, deploy.
# Running package also runs validate, compile, and test
mvn clean package
[INFO] --- maven-clean-plugin:3.3.2:clean ---
[INFO] --- maven-resources-plugin:3.3.1:resources ---
[INFO] --- maven-compiler-plugin:3.11.0:compile ---
[INFO] Compiling 8 source files to target/classes
[INFO] --- maven-resources-plugin:3.3.1:testResources ---
[INFO] --- maven-compiler-plugin:3.11.0:testCompile ---
[INFO] --- maven-surefire-plugin:3.2.2:test ---
[INFO] Tests run: 12, Failures: 0, Errors: 0, Skipped: 0
[INFO] --- maven-jar-plugin:3.3.0:jar ---
[INFO] Building jar: target/banking-common-1.1.0-SNAPSHOT.jar
[INFO] BUILD SUCCESS
What does each phase do?
Validate checks that the POM is well-formed and required properties exist. Compile compiles main source code into target/classes. Test runs unit tests with Surefire and stops the build if any test fails. Package bundles the compiled code into a JAR or WAR in target. Verify runs integration tests and quality checks. Install copies the packaged artifact into the local .m2 repository. Deploy uploads it to a remote shared repository.
package com.bank.common;
import java.math.BigDecimal;
import java.math.RoundingMode;
/**
* Shared utility for interest calculation across all NBI services.
* This is the library that gets installed/deployed.
*/
public class InterestCalculator {
public static BigDecimal simpleInterest(
BigDecimal principal, BigDecimal annualRate, int months) {
return principal
.multiply(annualRate)
.multiply(BigDecimal.valueOf(months))
.divide(BigDecimal.valueOf(1200), 2, RoundingMode.HALF_UP);
}
}
# Compile only
mvn compile
# Compile + test (build stops if tests fail)
mvn test
# Compile + test + package
mvn package
# Compile + test + package + verify (integration tests + quality gate)
mvn verify
What is the difference between mvn install and mvn deploy?
mvn install is local and private. It copies the built artifact into your machine's .m2 repository, so only projects on that same machine can resolve it as a dependency. This is perfect during local development when you build a shared library and want your other local project to use it immediately.
# Install to local .m2
mvn clean install
[INFO] --- maven-install-plugin:3.1.1:install ---
[INFO] Installing target/banking-common-1.1.0-SNAPSHOT.jar
[INFO] to /Users/rajesh/.m2/repository/com/bank/common/banking-common/1.1.0-SNAPSHOT/banking-common-1.1.0-SNAPSHOT.jar
[INFO] BUILD SUCCESS
mvn deploy is remote and shared. After doing everything install does, it uploads the artifact to a remote repository manager like Nexus or Artifactory. Now every developer and every CI pipeline in the organization can depend on that version.
# Deploy to shared repository (runs all phases including install first)
mvn clean deploy
[INFO] --- maven-deploy-plugin:3.1.1:deploy ---
[INFO] Uploading banking-common-1.1.0-SNAPSHOT.jar to
[INFO] https://nexus.nbi.com/repository/maven-snapshots/
[INFO] BUILD SUCCESS
What is distributionManagement?
The distributionManagement section in the POM configures where the deploy phase publishes artifacts. It defines a repository for releases and a snapshotRepository for snapshots. The id links to credentials stored in settings.xml, never in the POM.
<!-- pom.xml --syn-kw">>
syn-kw"><projectsyn-kw">>
syn-kw"><groupIdsyn-kw">>com.bank.commonsyn-kw"></groupIdsyn-kw">>
syn-kw"><artifactIdsyn-kw">>banking-commonsyn-kw"></artifactIdsyn-kw">>
syn-kw"><versionsyn-kw">>1.1.0-SNAPSHOTsyn-kw"></versionsyn-kw">>
syn-kw"><distributionManagementsyn-kw">>
syn-kw"><repositorysyn-kw">>
syn-kw"><idsyn-kw">>nbi-releasessyn-kw"></idsyn-kw">>
syn-kw"><urlsyn-kw">>https://nexus.nbi.com/repository/maven-releases/syn-kw"></urlsyn-kw">>
syn-kw"></repositorysyn-kw">>
syn-kw"><snapshotRepositorysyn-kw">>
syn-kw"><idsyn-kw">>nbi-snapshotssyn-kw"></idsyn-kw">>
syn-kw"><urlsyn-kw">>https://nexus.nbi.com/repository/maven-snapshots/syn-kw"></urlsyn-kw">>
syn-kw"></snapshotRepositorysyn-kw">>
syn-kw"></distributionManagementsyn-kw">>
syn-kw"></projectsyn-kw">>
<!-- settings.xml (in ~/.m2/) -- credentials stored here, not in POM --syn-kw">>
syn-kw"><settingssyn-kw">>
syn-kw"><serverssyn-kw">>
syn-kw"><serversyn-kw">>
syn-kw"><idsyn-kw">>nbi-releasessyn-kw"></idsyn-kw">>
syn-kw"><usernamesyn-kw">>ci-deployersyn-kw"></usernamesyn-kw">>
syn-kw"><passwordsyn-kw">>${env.NEXUS_PASSWORD}syn-kw"></passwordsyn-kw">>
syn-kw"></serversyn-kw">>
syn-kw"><serversyn-kw">>
syn-kw"><idsyn-kw">>nbi-snapshotssyn-kw"></idsyn-kw">>
syn-kw"><usernamesyn-kw">>ci-deployersyn-kw"></usernamesyn-kw">>
syn-kw"><passwordsyn-kw">>${env.NEXUS_PASSWORD}syn-kw"></passwordsyn-kw">>
syn-kw"></serversyn-kw">>
syn-kw"></serverssyn-kw">>
syn-kw"></settingssyn-kw">>
What is the difference between snapshot and release versions?
A version ending in -SNAPSHOT, like 1.1.0-SNAPSHOT, is a work-in-progress that can be re-published repeatedly. Maven appends a timestamp to each snapshot upload. A plain version like 1.0.0 is an immutable release that should never change once published. Treating released versions as immutable is critical for audits.
<!-- During development: snapshot --syn-kw">>
syn-kw"><versionsyn-kw">>1.1.0-SNAPSHOTsyn-kw"></versionsyn-kw">>
<!-- After release: immutable --syn-kw">>
syn-kw"><versionsyn-kw">>1.1.0syn-kw"></versionsyn-kw">>
# Snapshot can be re-deployed many times
mvn deploy
# Uploads: banking-common-1.1.0-20240115.103045-1.jar
mvn deploy
# Uploads: banking-common-1.1.0-20240115.143022-2.jar
# Release is deployed exactly once
# Attempting to re-deploy 1.1.0 to a release repo should fail
How does mvn deploy fit in a CI pipeline?
In a disciplined setup, developers rarely run deploy from their laptops. The CI server runs mvn deploy after tests pass on the main branch, so only reviewed, tested artifacts reach the shared repository.
# .github/workflows/deploy.yml
name: Deploy Library
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v4
with:
java-version: '21'
distribution: 'temurin'
- run: mvn clean deploy -s .mvn/settings.xml
env:
NEXUS_PASSWORD: ${{ secrets.NEXUS_PASSWORD }}
What are common mistakes?
The most common mistakes are hard-coding credentials in the POM, re-deploying a release version to overwrite it, running deploy from a laptop against the shared repository without review, and confusing install with deploy.
<!-- WRONG -- credentials in POM (visible to everyone who reads the POM) --syn-kw">>
syn-kw"><distributionManagementsyn-kw">>
syn-kw"><repositorysyn-kw">>
syn-kw"><idsyn-kw">>releasessyn-kw"></idsyn-kw">>
syn-kw"><urlsyn-kw">>https://nexus.nbi.com/repository/maven-releases/syn-kw"></urlsyn-kw">>
syn-kw"><usernamesyn-kw">>adminsyn-kw"></usernamesyn-kw">>
syn-kw"><passwordsyn-kw">>secret123syn-kw"></passwordsyn-kw">> <!-- NEVER do this --syn-kw">>
syn-kw"></repositorysyn-kw">>
syn-kw"></distributionManagementsyn-kw">>
<!-- CORRECT -- credentials in settings.xml, referenced by id --syn-kw">>
syn-kw"><distributionManagementsyn-kw">>
syn-kw"><repositorysyn-kw">>
syn-kw"><idsyn-kw">>nbi-releasessyn-kw"></idsyn-kw">>
syn-kw"><urlsyn-kw">>https://nexus.nbi.com/repository/maven-releases/syn-kw"></urlsyn-kw">>
syn-kw"></repositorysyn-kw">>
syn-kw"></distributionManagementsyn-kw">>
What should a senior engineer know?
A senior engineer knows that release immutability is a governance and audit requirement. If version 1.0.0 of a payments library could be silently overwritten, a security audit could never trust that the artifact in production matches what was reviewed. They know the Maven release plugin automates the strip-SNAPSHOT, tag, deploy, bump-to-next-SNAPSHOT workflow, and that the enforcer plugin can prevent snapshot dependencies in release builds.
Visual Overview
Maven Lifecycle Phases (ordered)
────────────────────────────────
┌──────────┐ ┌─────────┐ ┌──────┐ ┌─────────┐ ┌────────┐ ┌─────────┐ ┌────────┐
│ validate │─▶│ compile │─▶│ test │─▶│ package │─▶│ verify │─▶│ install │─▶│ deploy │
└──────────┘ └─────────┘ └──────┘ └─────────┘ └────────┘ └─────────┘ └────────┘
POM ok? src->class JUnit JAR/WAR integ tests local .m2 remote Nexus
mvn install vs mvn deploy:
┌───────────────────────────────────────────────────────┐
│ │
│ mvn install │
│ ┌────────┐ ┌───────────────────────┐ │
│ │ build │────▶│ ~/.m2/repository/ │ LOCAL │
│ │ JAR │ │ banking-common-1.1.0 │ only this │
│ └────────┘ └───────────────────────┘ machine │
│ │
│ mvn deploy │
│ ┌────────┐ ┌───────────────────────┐ │
│ │ build │────▶│ ~/.m2/repository/ │ LOCAL │
│ │ JAR │ └───────────────────────┘ │
│ │ │ ┌───────────────────────┐ │
│ │ │────▶│ Nexus / Artifactory │ SHARED │
│ │ │ │ everyone can download │ everyone │
│ └────────┘ └───────────────────────┘ │
│ │
└───────────────────────────────────────────────────────┘
Snapshot vs Release:
┌────────────────────────────┐ ┌────────────────────────────┐
│ 1.1.0-SNAPSHOT │ │ 1.1.0 (release) │
│ Can be re-published │ │ Immutable once published │
│ Timestamped uploads │ │ Overwrite should be blocked │
│ Goes to snapshotRepository │ │ Goes to repository │
└────────────────────────────┘ └────────────────────────────┘
Key Takeaway
The Maven default lifecycle is a fixed ordered sequence of phases -- validate, compile, test, package, verify, install, deploy -- and the key rule is that invoking any phase runs all phases before it. So when you run deploy, Maven quietly runs everything from validate through install first, giving you a single command that does the complete build.
The difference between install and deploy is scope and audience. mvn install copies the built artifact into your local .m2 repository so only projects on the same machine can use it, which is perfect for local development. mvn deploy does everything install does and then uploads the artifact to a shared repository like Nexus or Artifactory, so every developer and CI pipeline in the organization can depend on that version.
The distributionManagement section tells deploy where to publish, with separate URLs for release and snapshot repositories. Snapshot versions can be re-published repeatedly for work in progress, while release versions are immutable once published. Credentials are stored in settings.xml, never in the POM.
Remember one sentence: install publishes to your local .m2 for private use, deploy publishes to the shared Nexus or Artifactory for the whole organization, and release versions are immutable because a bank's audit must trust that what runs in production matches what was reviewed.
---