The pom.xml (Project Object Model) is the central file of every Maven project. It is an XML document that describes the project: its identity, its dependencies, its properties, and how to build it.
Every pom.xml starts with a <project> root and its namespace, and must declare the model version:
<?xml version="1.0" encoding="UTF-8"?>
<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>
<!-- The rest of the configuration here -->
</project>
<modelVersion>4.0.0</modelVersion>is mandatory and is always4.0.0today: it is the version of thepom.xmlfile format, not the version of your project.
A pom.xml is read from top to bottom, in large blocks. Here is the typical organization:
| Block | Role |
|---|---|
<modelVersion> | Format version (always 4.0.0) |
<groupId> / <artifactId> / <version> | Coordinates (project identity) |
<packaging> | Artifact type (jar, war, pom) |
<properties> | Reusable variables (versions, encoding) |
<dependencies> | Libraries in use (lesson 03) |
<build> | Plugins and build configuration |
The <packaging> block determines the deliverable type:
| Value | Product |
|---|---|
jar | Java library or application (default) |
war | Web application deployable on a server |
pom | “Parent” project with no code (aggregator) |
If you omit
<packaging>, Maven choosesjarby default. Once again: convention over configuration.
🔧 Mini-exercise — Write the <packaging> tag that produces a web application deployable on Tomcat.
<packaging>war</packaging>Every Maven project is identified uniquely by three coordinates, often abbreviated GAV: GroupId, ArtifactId, Version.
<groupId>com.exemple</groupId>
<artifactId>mon-app</artifactId>
<version>1.0.0</version>| Coordinate | Meaning | Convention |
|---|---|---|
| groupId | The organization / the project | Reversed domain name: com.exemple |
| artifactId | The module name | Short, lowercase: mon-app |
| version | The current version | Numeric: 1.0.0, or 1.0.0-SNAPSHOT |
The -SNAPSHOT suffix deserves special attention:
| Version | Meaning |
|---|---|
1.0.0-SNAPSHOT | Version in development, unstable, updated frequently |
1.0.0 | Published version (release), frozen and immutable |
# The produced artifact name combines artifactId + version
# e.g. mon-app-1.0.0-SNAPSHOT.jar
mvn packageThe combination
groupId:artifactId:versionis your project's “postal address” in the Maven ecosystem. That is how other projects will be able to depend on it.
🔧 Mini-exercise — Write the three GAV tags for a com.banque project named gestion-comptes in development version 1.0.0.
<groupId>com.banque</groupId>
<artifactId>gestion-comptes</artifactId>
<version>1.0.0-SNAPSHOT</version>The <properties> block defines reusable variables throughout the pom.xml. You centralize versions and settings there to avoid repetition.
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<junit.version>5.10.2</junit.version>
</properties>You then reuse a property with the ${name} syntax:
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>${junit.version}</version> <!-- reuses the property -->
<scope>test</scope>
</dependency>Common properties:
| Property | Role |
|---|---|
maven.compiler.source / target | Java version of the source code and the bytecode |
project.build.sourceEncoding | File encoding (always UTF-8) |
Custom properties (junit.version…) | Centralize version numbers |
Centralizing versions in
<properties>is good practice: to move JUnit from 5.10 to 5.11, you change one place instead of every dependency.
🔧 Mini-exercise — Define a gson.version property set to 2.10.1, then show how to reuse it in a <version> tag.
<properties>
<gson.version>2.10.1</gson.version>
</properties>
<!-- ... -->
<version>${gson.version}</version>A pom.xml can inherit from another pom.xml via the <parent> block. The child then receives the parent's properties, dependencies, and configuration. This is the mechanism that lets you factor configuration shared by several modules.
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.5</version>
<relativePath/> <!-- empty: look up the parent in the repository -->
</parent>The best-known use is the Spring Boot parent, which pins the versions of dozens of libraries so they stay compatible with each other. Thanks to it, you declare dependencies without specifying their version:
<!-- No <version>: it is inherited from the parent -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>| With parent inheritance | Without parent inheritance |
|---|---|
| Consistent versions guaranteed | Risk of incompatible versions |
| Less repeated configuration | Everything to redeclare in each module |
The Spring Boot parent acts as a “validated shopping list”: it guarantees that all your libraries get along, without you having to pick every version number by hand.
Here is a realistic pom.xml that brings together everything above: coordinates, properties, optional parent, and dependencies.
<?xml version="1.0" encoding="UTF-8"?>
<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">
<!-- File format version -->
<modelVersion>4.0.0</modelVersion>
<!-- GAV coordinates: project identity -->
<groupId>com.exemple</groupId>
<artifactId>mon-app</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>jar</packaging>
<!-- Reusable variables -->
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<junit.version>5.10.2</junit.version>
</properties>
<!-- Libraries in use -->
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>You can display the “effective” pom.xml (with all inheritance resolved):
# Shows the complete pom, parent included
mvn help:effective-pomThe
mvn help:effective-pomcommand is invaluable for understanding what Maven actually “sees”, including everything that comes from the parent.
🔧 Mini-exercise — Write the command that displays the effective pom.xml, with all parent inheritance resolved.
mvn help:effective-pomQuestion 1: What do the three GAV coordinates stand for?
a) Group, Action, Value
b) GroupId, ArtifactId, Version
c) Git, Apache, Version
d) General, Application, Version
Answer: b) — GAV = groupId, artifactId, version: the project's unique identity.
Question 2: What does the -SNAPSHOT suffix mean in a version?
a) A published, frozen version
b) A version in development, unstable and updated frequently
c) A screenshot of the project
d) An obsolete version
Answer: b) — -SNAPSHOT marks a development version. A version without that suffix is a frozen release.
Question 3: What is the <properties> block for?
a) Declaring dependencies
b) Defining reusable variables (versions, encoding) with ${...}
c) Configuring the web server
d) Writing Java code
Answer: b) — Properties centralize reusable values via the ${name} syntax, avoiding repetition.
Question 4: What is the benefit of inheriting from a <parent> such as spring-boot-starter-parent?
a) It removes the need for code
b) It guarantees consistent library versions and reduces configuration
c) It speeds up the network
d) It encrypts the pom.xml
Answer: b) — The parent pins mutually compatible versions; you can then declare dependencies without specifying their version.
Question 5: What value does <modelVersion> always take today?
a) 1.0.0
b) 3.9.6
c) 4.0.0
d) 17
Answer: c) — <modelVersion>4.0.0</modelVersion> is the version of the pom.xml file format, mandatory and unchanging.
Write a pom.xml from scratch for a project identified by com.banque:gestion-comptes:1.0.0-SNAPSHOT, packaged as a jar, compiled as Java 17 with UTF-8 encoding, and centralizing the JUnit version in a property. Then verify it.
<?xml version="1.0" encoding="UTF-8"?>
<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.banque</groupId>
<artifactId>gestion-comptes</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<junit.version>5.10.2</junit.version>
</properties>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>Verification:
# Check that the pom is valid and resolvable
mvn validate
# Display the effective pom (parent and properties resolved)
mvn help:effective-pomExpected result:
[INFO] BUILD SUCCESSIf
mvn validateprintsBUILD SUCCESS, yourpom.xmlis syntactically correct and all its coordinates are well formed. A common mistake: forgetting<modelVersion>or leaving an XML tag unclosed.
pom.xml is an XML file that describes identity, properties, dependencies, and build.groupId, artifactId, version) identify the project uniquely.-SNAPSHOT = version in development; without the suffix = frozen published version.<properties> centralize reusable variables via ${name}.<parent> inheritance factors configuration and guarantees consistent versions.Lesson 03 — Dependency management: declare libraries, understand scopes, repositories, and transitive resolution.
All rights reserved. Any reproduction, distribution, use or adaptation of this course, in whole or in part, is strictly prohibited without the prior written authorization of Dr. Haythem REHOUMA.
Course created by Dr. Haythem REHOUMA — Development and Deployment of Data Solutions