Maven: Project Structure and pom.xml
Every Maven project is defined by a single file: pom.xml (Project Object Model). It tells Maven how to build your project, what dependencies it needs, and how to package it.
Standard Directory Layout
my-project/
├── pom.xml ← Project definition
├── src/
│ ├── main/
│ │ ├── java/ ← Application source code
│ │ │ └── com/myapp/
│ │ │ └── App.java
│ │ └── resources/ ← Config files, properties
│ │ └── application.properties
│ └── test/
│ ├── java/ ← Test source code
│ │ └── com/myapp/
│ │ └── AppTest.java
│ └── resources/ ← Test config files
│ └── test-data.csv
└── target/ ← Build output (generated)
├── classes/
├── test-classes/
└── my-project-1.0.0.jar
Convention over configuration: Maven expects this layout. Don’t fight it — follow it.
Creating a Maven Project
mvn archetype:generate \
-DgroupId=com.myapp \
-DartifactId=my-project \
-DarchetypeArtifactId=maven-archetype-quickstart \
-DarchetypeVersion=1.5 \
-DinteractiveMode=false
Or simply create the directory structure and pom.xml manually.
pom.xml Anatomy
<?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>
<!-- ═══ GAV Coordinates ═══ -->
<groupId>com.myapp</groupId>
<artifactId>my-project</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<name>My Project</name>
<description>A sample Maven project</description>
<!-- ═══ Properties ═══ -->
<properties>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<junit.version>5.10.3</junit.version>
</properties>
<!-- ═══ Dependencies ═══ -->
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<!-- ═══ Build Configuration ═══ -->
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.13.0</version>
<configuration>
<release>21</release>
</configuration>
</plugin>
</plugins>
</build>
</project>
GAV Coordinates
Every Maven artifact is uniquely identified by three values:
| Element | Purpose | Example |
|---|---|---|
groupId |
Organization/domain (reversed) | com.myapp |
artifactId |
Project name | my-project |
version |
Release version | 1.0.0 |
com.myapp:my-project:1.0.0
This is how Maven finds artifacts in repositories.
Properties
Properties are variables you can reuse throughout the POM:
<properties>
<java.version>21</java.version>
<spring-boot.version>3.3.0</spring-boot.version>
<lombok.version>1.18.34</lombok.version>
</properties>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version> <!-- references property -->
</dependency>
</dependencies>
Built-in Properties
| Property | Value |
|---|---|
${project.version} |
Current project version |
${project.basedir} |
Project root directory |
${project.build.directory} |
target/ |
${java.home} |
JDK installation path |
Packaging Types
<packaging>jar</packaging> <!-- default — executable JAR -->
<packaging>war</packaging> <!-- web application -->
<packaging>pom</packaging> <!-- parent/BOM — no code -->
Parent POM and Inheritance
<!-- Parent POM (shared settings) -->
<project>
<groupId>com.myapp</groupId>
<artifactId>parent</artifactId>
<version>1.0.0</version>
<packaging>pom</packaging>
<properties>
<java.version>21</java.version>
</properties>
<dependencyManagement>
<dependencies>
<!-- Versions defined here, children don't need version -->
</dependencies>
</dependencyManagement>
</project>
<!-- Child POM -->
<project>
<parent>
<groupId>com.myapp</groupId>
<artifactId>parent</artifactId>
<version>1.0.0</version>
</parent>
<artifactId>user-service</artifactId>
<!-- inherits groupId, version, properties from parent -->
</project>
The Super POM
Every POM implicitly extends Maven’s Super POM, which defines:
- Maven Central repository
- Standard directory layout
- Default plugin versions
View the merged result:
mvn help:effective-pom
This shows the effective POM — your POM + parent POM + Super POM merged together.
Common Mistakes
| Mistake | Fix |
|---|---|
| Non-standard directory structure | Stick to src/main/java and src/test/java |
| Hardcoded versions everywhere | Use <properties> for version management |
Missing <packaging> |
Defaults to jar — explicit is better |
Editing files in target/ |
target/ is generated — edit source, rebuild |
Key Takeaways
pom.xmlis the single source of truth for a Maven project.- GAV coordinates (
groupId:artifactId:version) uniquely identify every artifact. - Follow the standard directory layout — Maven expects it.
- Use
<properties>for version management. - Parent POMs share configuration across multiple modules.
What’s Next?
Next: Maven Lifecycle, Goals, and Phases — understand what happens when you run mvn package.