Your First Maven Project

This chapter gets your hands dirty. You will create two Maven projects: one using a built-in project template called an archetype, and another from scratch. By the end, you will understand the standard directory layout, the basic build commands, and how Maven turns source code into a runnable JAR.

Prerequisites

  • JDK 21 installed
  • Maven installed and working (mvn -version returns 3.9.x)
  • A terminal or command prompt ready

Creating a Project with an Archetype

An archetype is a project template. Maven ships with a default one called maven-archetype-quickstart that gives you a minimal Java project with a HelloWorld class and a matching unit test.

Generating the Skeleton

Open your terminal, navigate to a folder where you keep projects, and run:

bash
# Generate a new project from the quickstart archetype
mvn archetype:generate \
  -DgroupId=com.example \
  -DartifactId=my-first-app \
  -DarchetypeArtifactId=maven-archetype-quickstart \
  -DarchetypeVersion=1.5 \
  -DinteractiveMode=false

Maven downloads the archetype plugin and the template itself, then creates a new folder named my-first-app. The arguments mean:

ArgumentMeaning
groupIdYour organization's reverse domain name (like a package prefix)
artifactIdThe name of the project (also the folder name)
archetypeArtifactIdWhich template to use
archetypeVersionVersion of the template
interactiveMode=falseSkip the interactive wizard and use defaults

The Directory Structure

After generation, my-first-app looks like this:

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

Each directory has a specific job:

DirectoryPurpose
src/main/javaApplication source code
src/main/resourcesConfiguration files, images, templates (empty at first)
src/test/javaUnit test source code
src/test/resourcesTest-specific configuration files (empty at first)
pom.xmlThe project object model — Maven's configuration file

Tip

Convention over Configuration in Action

Notice you never told Maven where to put Java files. It simply knows that src/main/java is the default source directory because every Maven project follows this convention.

Building and Running

Navigate into the project folder:

bash
cd my-first-app

Compile the source code:

bash
# Compile main sources
mvn compile

You should see BUILD SUCCESS and a new target/ folder containing compiled .class files.

Package the project into a JAR:

bash
# Compile, test, and package
mvn package

This produces target/my-first-app-1.0-SNAPSHOT.jar. Try to run it:

bash
# Attempt to run the JAR
java -jar target/my-first-app-1.0-SNAPSHOT.jar

You will get an error: no main manifest attribute. The quickstart archetype does not configure an executable JAR by default. For now, run the class directly:

bash
# Run the main class with the classpath set to target/classes
java -cp target/classes com.example.App

You should see Hello World!.

Creating a Minimal Project by Hand

Archetypes are convenient, but understanding what they hide is essential. Let us build the same project from scratch without any template.

Step 1: Create the Directories

In a fresh folder named minimal-project, create the structure manually:

bash
# Create the standard Maven directories
mkdir -p src/main/java/com/example
mkdir -p src/test/java/com/example

Step 2: Write the POM

Create a file named pom.xml in the project root with this content:

xml
<?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">
    <!-- Maven POM model version -->
    <modelVersion>4.0.0</modelVersion>
 
    <!-- Project coordinates -->
    <groupId>com.example</groupId>
    <artifactId>minimal-project</artifactId>
    <version>1.0-SNAPSHOT</version>
 
    <!-- Compiler settings -->
    <properties>
        <maven.compiler.source>21</maven.compiler.source>
        <maven.compiler.target>21</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
</project>

Step 3: Write the Java Class

Create src/main/java/com/example/HelloWorld.java:

java
package com.example;
 
public class HelloWorld {
 
    public static void main(String[] args) {
        // Print a greeting to the console
        System.out.println("Hello from hand-built Maven!");
    }
}

Step 4: Build and Run

Run the same commands as before:

bash
# Compile the project
mvn compile
 
# Package into a JAR
mvn package

Again, the generated JAR is not executable out of the box. Run the class directly:

bash
# Execute the main class
java -cp target/classes com.example.HelloWorld

You should see Hello from hand-built Maven!.

Tip

What About the Test Folder?

We created src/test/java but left it empty. Maven does not complain — it simply has no tests to run. In the next chapters, you will add JUnit tests there.

The Target Directory

Every build command creates or updates the target/ directory. Here is what you will find inside after mvn package:

text
target/
  classes/                  # Compiled .class files from src/main/java
  test-classes/             # Compiled .class files from src/test/java (if any)
  maven-archiver/           # Metadata used by the jar plugin
  minimal-project-1.0-SNAPSHOT.jar   # The final artifact

You should never commit target/ to version control. It is a build output, not source code. Add it to .gitignore:

text
# Maven build output
target/

FAQ

Why does java -jar fail with "no main manifest attribute"?

A JAR file needs a MANIFEST.MF entry pointing to the main class in order to be executable with java -jar. The quickstart archetype and a bare-bones POM do not add this by default. We will fix that in the Plugins chapter using maven-jar-plugin.

Can I change the default directory structure?

Yes, but you rarely should. You can override src/main/java and other paths in pom.xml, but doing so breaks the convention that every Java developer expects. Stick to the defaults unless you have a compelling reason.

What is 1.0-SNAPSHOT?

SNAPSHOT means the project is under active development. Maven treats snapshot versions specially — it checks for updated artifacts on every build instead of caching them forever. When you release a stable version, you drop the SNAPSHOT suffix.

Do I need to run mvn compile before mvn package?

No. package is a later phase in the same lifecycle, so it automatically triggers compile and every phase before it. Running mvn package alone is enough.

Why does Maven download so many files on the first run?

Maven caches plugins and dependencies in ~/.m2/repository. The first time you use a plugin or a dependency, Maven downloads it from the internet. After that, builds are much faster because everything is local.