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 -versionreturns 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:
# 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=falseMaven downloads the archetype plugin and the template itself, then creates a new folder named my-first-app. The arguments mean:
| Argument | Meaning |
|---|---|
groupId | Your organization's reverse domain name (like a package prefix) |
artifactId | The name of the project (also the folder name) |
archetypeArtifactId | Which template to use |
archetypeVersion | Version of the template |
interactiveMode=false | Skip the interactive wizard and use defaults |
The Directory Structure
After generation, my-first-app looks like this:
my-first-app/
pom.xml
src/
main/
java/
com/
example/
App.java
test/
java/
com/
example/
AppTest.javaEach directory has a specific job:
| Directory | Purpose |
|---|---|
src/main/java | Application source code |
src/main/resources | Configuration files, images, templates (empty at first) |
src/test/java | Unit test source code |
src/test/resources | Test-specific configuration files (empty at first) |
pom.xml | The 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:
cd my-first-appCompile the source code:
# Compile main sources
mvn compileYou should see BUILD SUCCESS and a new target/ folder containing compiled .class files.
Package the project into a JAR:
# Compile, test, and package
mvn packageThis produces target/my-first-app-1.0-SNAPSHOT.jar. Try to run it:
# Attempt to run the JAR
java -jar target/my-first-app-1.0-SNAPSHOT.jarYou 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:
# Run the main class with the classpath set to target/classes
java -cp target/classes com.example.AppYou 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:
# Create the standard Maven directories
mkdir -p src/main/java/com/example
mkdir -p src/test/java/com/exampleStep 2: Write the POM
Create a file named pom.xml in the project root with this content:
<?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:
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:
# Compile the project
mvn compile
# Package into a JAR
mvn packageAgain, the generated JAR is not executable out of the box. Run the class directly:
# Execute the main class
java -cp target/classes com.example.HelloWorldYou 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:
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 artifactYou should never commit target/ to version control. It is a build output, not source code. Add it to .gitignore:
# 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.