Introduction to Maven

Every Java project beyond a single file needs to manage dependencies. You need a testing framework, a logging library, a database driver. Downloading JAR files manually and managing classpaths gets tedious fast. Maven solves this.

Maven is a build tool that handles dependency management, compilation, testing, packaging, and deployment. You describe what your project needs in an XML file, and Maven figures out the rest. It downloads libraries, compiles your code, runs tests, and packages everything into a JAR or WAR file.

This tutorial covers Maven fundamentals: project structure, the POM file, dependency management, and common commands you’ll use daily.

Installing Maven

Maven requires Java. Verify you have Java installed first:

java -version

Windows:

  1. Download the binary zip from maven.apache.org/download.cgi
  2. Extract to a folder like C:\Program Files\Apache\maven
  3. Add the bin folder to your PATH environment variable
  4. Set MAVEN_HOME to the Maven folder

macOS (with Homebrew):

brew install maven

Linux (Debian/Ubuntu):

sudo apt update
sudo apt install maven

Verify the installation:

mvn -version

You should see Maven’s version, Java version, and OS information.

Creating a Maven Project

Maven can generate a project skeleton using archetypes (templates). The quickstart archetype creates a simple Java application:

mvn archetype:generate \
  -DgroupId=com.example \
  -DartifactId=my-app \
  -DarchetypeArtifactId=maven-archetype-quickstart \
  -DarchetypeVersion=1.4 \
  -DinteractiveMode=false

This creates a folder called my-app with the standard Maven structure:

my-app/
    pom.xml
    src/
        main/
            java/
                com/
                    example/
                        App.java
        test/
            java/
                com/
                    example/
                        AppTest.java

The structure is standardized. Every Maven project follows this layout, which means you can jump into any Maven project and immediately know where to find things.

src/main/java: Your application source code.

src/main/resources: Configuration files, properties, XML files that get included in the build.

src/test/java: Test source code.

src/test/resources: Test-specific resources.

target/: Generated output (compiled classes, JAR files). Maven creates this folder. Don’t commit it to version control.

The POM File

The pom.xml file is Maven’s configuration. POM stands for Project Object Model. It defines your project’s identity, dependencies, build settings, and plugins.

Here’s a basic POM:

<?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.example</groupId>
    <artifactId>my-app</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>
    
    <name>My Application</name>
    <description>A sample Maven project</description>
    
    <properties>
        <maven.compiler.source>21</maven.compiler.source>
        <maven.compiler.target>21</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    
    <dependencies>
        <!-- Dependencies go here -->
    </dependencies>
    
</project>

Project Coordinates

Three elements uniquely identify a Maven project:

groupId: Usually your organization’s domain in reverse. Like a package name. Examples: com.google, org.apache, com.example.

artifactId: The project name. Should be lowercase with hyphens. Examples: my-app, spring-core, junit-jupiter.

version: The project version. SNAPSHOT indicates a development version. Releases drop the SNAPSHOT suffix.

Together, these form coordinates that uniquely identify any artifact in the Maven ecosystem. When you add a dependency, you specify its coordinates.

Properties

The properties section defines variables you can reference elsewhere in the POM:

<properties>
    <maven.compiler.source>21</maven.compiler.source>
    <maven.compiler.target>21</maven.compiler.target>
    <junit.version>5.10.1</junit.version>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

Reference properties with ${property.name}:

<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter</artifactId>
    <version>${junit.version}</version>
    <scope>test</scope>
</dependency>

Managing Dependencies

Dependencies are libraries your project needs. Add them to the dependencies section of your POM:

<dependencies>
    <!-- JUnit 5 for testing -->
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter</artifactId>
        <version>5.10.1</version>
        <scope>test</scope>
    </dependency>
    
    <!-- Google Gson for JSON parsing -->
    <dependency>
        <groupId>com.google.code.gson</groupId>
        <artifactId>gson</artifactId>
        <version>2.10.1</version>
    </dependency>
    
    <!-- SLF4J logging -->
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>2.0.9</version>
    </dependency>
</dependencies>

Maven downloads these JARs automatically from the Maven Central repository. It also downloads their dependencies (transitive dependencies). Gson might need other libraries, and Maven fetches those too.

Finding Dependencies

Search for libraries on search.maven.org or mvnrepository.com. These sites show the XML snippet to copy into your POM.

Dependency Scope

The scope element controls when a dependency is available:

compile (default): Available everywhere. Included in the final package.

test: Only available during testing. JUnit, Mockito, and other test libraries use this.

provided: Available during compilation but not packaged. The runtime environment provides it. Servlet API uses this since the web server provides it.

runtime: Not needed for compilation but required at runtime. JDBC drivers often use this.

<!-- Only for tests -->
<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter</artifactId>
    <version>5.10.1</version>
    <scope>test</scope>
</dependency>

<!-- Server provides this -->
<dependency>
    <groupId>jakarta.servlet</groupId>
    <artifactId>jakarta.servlet-api</artifactId>
    <version>6.0.0</version>
    <scope>provided</scope>
</dependency>

<!-- Only needed at runtime -->
<dependency>
    <groupId>com.mysql</groupId>
    <artifactId>mysql-connector-j</artifactId>
    <version>8.2.0</version>
    <scope>runtime</scope>
</dependency>

Maven Commands

Run Maven commands from the directory containing pom.xml.

mvn compile

Compiles your source code. Output goes to target/classes.

mvn compile

mvn test

Runs tests using JUnit or another test framework. Also compiles if needed.

mvn test

mvn package

Compiles, tests, and packages the project into a JAR (or WAR for web apps). The output goes to target/.

mvn package

After running this, you’ll have target/my-app-1.0-SNAPSHOT.jar.

mvn install

Does everything package does, then installs the JAR to your local Maven repository (~/.m2/repository). Other local projects can then use it as a dependency.

mvn install

mvn clean

Deletes the target/ directory. Use this to start fresh.

mvn clean

Combine commands:

mvn clean package    # Clean, then package
mvn clean install    # Clean, then install

mvn dependency:tree

Shows all dependencies including transitive ones. Useful for debugging version conflicts.

mvn dependency:tree

Output shows the dependency hierarchy:

[INFO] com.example:my-app:jar:1.0-SNAPSHOT
[INFO] +- com.google.code.gson:gson:jar:2.10.1:compile
[INFO] +- org.slf4j:slf4j-api:jar:2.0.9:compile
[INFO] \- org.junit.jupiter:junit-jupiter:jar:5.10.1:test
[INFO]    +- org.junit.jupiter:junit-jupiter-api:jar:5.10.1:test
[INFO]    |  +- org.opentest4j:opentest4j:jar:1.3.0:test
[INFO]    |  \- org.junit.platform:junit-platform-commons:jar:1.10.1:test
...

The Build Lifecycle

Maven has a defined build lifecycle with phases that execute in order. When you run a phase, all previous phases run first.

The main phases in order:

  1. validate: Check project is correct
  2. compile: Compile source code
  3. test: Run unit tests
  4. package: Create JAR/WAR
  5. verify: Run integration tests
  6. install: Install to local repository
  7. deploy: Copy to remote repository

Running mvn package automatically runs validate, compile, and test first. Running mvn install runs everything through package, then install.

Plugins

Plugins extend Maven’s capabilities. You configure them in the build section:

<build>
    <plugins>
        <!-- Compiler plugin - set Java version -->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.11.0</version>
            <configuration>
                <source>21</source>
                <target>21</target>
            </configuration>
        </plugin>
        
        <!-- JAR plugin - configure manifest -->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-jar-plugin</artifactId>
            <version>3.3.0</version>
            <configuration>
                <archive>
                    <manifest>
                        <mainClass>com.example.App</mainClass>
                    </manifest>
                </archive>
            </configuration>
        </plugin>
    </plugins>
</build>

Creating an Executable JAR

A regular JAR doesn’t include dependencies. The maven-shade-plugin creates a “fat JAR” with everything bundled:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-shade-plugin</artifactId>
    <version>3.5.1</version>
    <executions>
        <execution>
            <phase>package</phase>
            <goals>
                <goal>shade</goal>
            </goals>
            <configuration>
                <transformers>
                    <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                        <mainClass>com.example.App</mainClass>
                    </transformer>
                </transformers>
            </configuration>
        </execution>
    </executions>
</plugin>

After mvn package, run the JAR directly:

java -jar target/my-app-1.0-SNAPSHOT.jar

Running Your Application

The exec-maven-plugin lets you run your application from Maven:

<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>exec-maven-plugin</artifactId>
    <version>3.1.1</version>
    <configuration>
        <mainClass>com.example.App</mainClass>
    </configuration>
</plugin>

Run with:

mvn exec:java

A Complete POM Example

Here’s a practical POM for a command-line application:

<?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.example</groupId>
    <artifactId>my-app</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>
    
    <name>My Application</name>
    
    <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.1</junit.version>
    </properties>
    
    <dependencies>
        <!-- JSON parsing -->
        <dependency>
            <groupId>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
            <version>2.10.1</version>
        </dependency>
        
        <!-- HTTP client -->
        <dependency>
            <groupId>com.squareup.okhttp3</groupId>
            <artifactId>okhttp</artifactId>
            <version>4.12.0</version>
        </dependency>
        
        <!-- Logging -->
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.4.14</version>
        </dependency>
        
        <!-- Testing -->
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter</artifactId>
            <version>${junit.version}</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
    
    <build>
        <plugins>
            <!-- Surefire plugin for running tests -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>3.2.3</version>
            </plugin>
            
            <!-- Create executable JAR -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-shade-plugin</artifactId>
                <version>3.5.1</version>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>shade</goal>
                        </goals>
                        <configuration>
                            <transformers>
                                <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                                    <mainClass>com.example.App</mainClass>
                                </transformer>
                            </transformers>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
    
</project>

IDE Integration

All major IDEs support Maven natively.

IntelliJ IDEA: Open the pom.xml file directly. IntelliJ imports the project automatically. The Maven tool window (View > Tool Windows > Maven) shows lifecycle phases and plugins you can run with a click.

Eclipse: File > Import > Maven > Existing Maven Projects. Point to the folder containing pom.xml.

VS Code: Install the “Extension Pack for Java” which includes Maven support. Open the folder containing pom.xml.

IDEs automatically download dependencies, update the classpath, and provide code completion for classes in your dependencies.

The Local Repository

Maven downloads dependencies to a local repository at ~/.m2/repository (on Windows, C:\Users\YourName\.m2\repository). This cache means Maven only downloads each artifact once.

If a dependency seems corrupted or you want to force a fresh download:

# Delete specific dependency
rm -rf ~/.m2/repository/com/google/code/gson

# Force update
mvn clean install -U

The -U flag forces Maven to check for updated snapshots and releases.

Maven vs Gradle

Gradle is another popular build tool. It uses Groovy or Kotlin instead of XML, which some developers prefer. Spring Boot projects often use Gradle.

Maven advantages: More mature, more documentation, simpler to understand, XML is more explicit.

Gradle advantages: Faster builds, more flexible, less verbose configuration, better for complex multi-project builds.

Both work well. Many organizations have standardized on one or the other. Learn whichever your team uses, and you can pick up the other quickly since the concepts are similar.

Common Issues

“Could not resolve dependencies”: Check your internet connection. Verify the dependency coordinates are correct. Try mvn clean install -U to force updates.

“Source option 5 is no longer supported”: Your POM doesn’t specify a Java version. Add the maven.compiler.source and maven.compiler.target properties.

Tests not running: Make sure test class names end with “Test” (like UserServiceTest). Maven’s Surefire plugin uses naming conventions to find tests.

JAR not executable: You need to configure the main class in the manifest. Use the maven-jar-plugin or maven-shade-plugin as shown above.


Previous: Introduction to JDBC

Related: How to Install Java | Best Java IDEs Compared | Setting Up Java in VS Code

Sources

  • Apache. “Maven Getting Started Guide.” maven.apache.org/guides/getting-started
  • Apache. “POM Reference.” maven.apache.org/pom.html
  • Apache. “Maven Central Repository.” search.maven.org
Scroll to Top