Maven: Getting Started
|
This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production. The reference material consulted while preparing these pages is listed in the section bibliography. |
This page is written against Apache Maven 3.10.0 (released on 27 September 2026). Every example marked as run was executed on JDK 26
on 2026-10-16, on macOS, in a scratch directory, with Maven 3.10.0 unless the text names another version; output is shown as printed, with
the long scratch path shortened to <scratch> (and the private local repository used in two runs to <repo>). Output that is
shortened with a grep or by removing blank lines or Loaded ... prefixes lines says so. The page follows the official "Maven in 5
Minutes" and "Getting Started Guide", which it checks against what current Maven prints, and ends with the places where those guides
are out of date. The running scenario of this section, tidepool, comes back at the end for the "more than one project" question; the
ideas behind the commands (layout and coordinates) are on
Philosophy, Coordinates & Directory Layout.
If you are new to Java build and tooling in general, Java: Build & Tooling places
Maven among the tools a Java developer meets.
Prerequisites
You need a JDK and Maven. The installation, including verifying the download, is on Installation; here it is enough to check that both work:
mvn --version
Apache Maven 3.10.0 (c43a36b8d67be7e0805a411bc0898af1a51f5472)
Maven home: <tools>/apache-maven-3.10.0
Java version: 26, vendor: Oracle Corporation, runtime: /Library/Java/JavaVirtualMachines/jdk-26.jdk/Contents/Home
Default locale: es_ES, platform encoding: UTF-8, time zone: Europe/Madrid
OS name: "mac os x", version: "27.0.1", arch: "aarch64", family: "mac"
(<tools> stands for the directory the distribution was unpacked into.) The "Maven home" line shows which installation answered, and the
"Java version" line which JDK it will run on, which is the first thing to check when a build behaves oddly. Maven 3.10.0 and 3.9.16
need Java 8 or later to run; Maven 4.0.0-rc-7 needs Java 17. The Java a project is compiled for is a separate choice, made in the
POM (below). Behind a proxy or with a non-default local repository you also need some configuration; see
Configuring Maven and
settings.xml & Password Encryption.
Source: Maven in 5 Minutes: Installation
Creating a project
Maven’s answer to "how do I start" is the archetype: a project template that is combined with some input to produce a working project.
The archetype:generate goal (from the Maven Archetype plugin, version 3.4.1 in these runs) creates a project from one. The simplest
template is maven-archetype-quickstart, whose latest release on Maven Central on 2026-10-16 is 1.5. The command of the official guide,
run unchanged in an empty directory (the flags -B for batch mode and -ntp for no transfer progress were added to keep the log
readable and are covered on the Running Maven page):
mvn -B -ntp archetype:generate -DgroupId=com.mycompany.app -DartifactId=my-app \
-DarchetypeArtifactId=maven-archetype-quickstart -DarchetypeVersion=1.5 -DinteractiveMode=false
[INFO] --- archetype:3.4.1:generate (default-cli) @ standalone-pom ---
[INFO] Generating project in Batch mode
[INFO] ----------------------------------------------------------------------------
[INFO] Using following parameters for creating project from Archetype: maven-archetype-quickstart:1.5
[INFO] ----------------------------------------------------------------------------
[INFO] Parameter: groupId, Value: com.mycompany.app
[INFO] Parameter: artifactId, Value: my-app
[INFO] Parameter: version, Value: 1.0-SNAPSHOT
[INFO] Parameter: package, Value: com.mycompany.app
[INFO] Parameter: packageInPathFormat, Value: com/mycompany/app
[INFO] Parameter: junitVersion, Value: 5.11.0
[INFO] Parameter: javaCompilerVersion, Value: 17
[INFO] Project created from Archetype in dir: <scratch>/my-app
[INFO] BUILD SUCCESS
(Output filtered to the lines that carry information; the run also repeated a few Parameter lines.) Three things in that output
are worth reading rather than skipping:
-
@ standalone-pommeans the goal ran outside any project, against Maven’s built-in empty POM.archetype:generatecreates a project; it does not need one. -
The goal was called by its short prefix
archetype, which Maven maps to the pluginorg.apache.maven.plugins:maven-archetype-pluginand then resolves to its latest release (3.4.1 here). A repeatable build names the plugin version explicitly, as the generated POM does for the lifecycle plugins (below). -
The parameters not given on the command line took their defaults: the version
1.0-SNAPSHOT, the Java package equal to the group id, JUnit 5.11.0 and Java 17 as the compiler release. They can all be set with-Doptions.
The same command also printed a few Don't override file warnings for directories that the archetype generated and that already
existed in the target path (src/main/java/com/mycompany/app, the test equivalent and .mvn); they are noise on a first run. Maven 3.10.0
and 4.0.0-rc-7 (not 3.9.16) additionally printed a warning that Maven Central serves the path archetype-catalog.xml which the repository’s
auto-discovered prefixes file denies and that "the prefixes file appears stale"; Maven allowed that one verified path and carried on. It comes from the auto-discovered repository prefixes that the same log reports loading (Loaded 24109 auto-discovered prefixes for remote repository central), and it is harmless here.
The first run downloads
The guide warns that the first run "may take a while" because Maven downloads plugins and their dependencies into the local
repository, and that a flaky connection can make you repeat the command. This is measurable. The same generation followed by
mvn package, each against an empty private local repository (-Dmaven.repo.local), on a fast connection (the time is the total Maven reported):
| Run | Downloads | Total time |
|---|---|---|
|
149 files |
4.4 s |
|
152 files |
6.1 s |
the local repository afterwards |
102 JARs |
81 MB |
Every later build of any project reuses what is in ~/.m2/repository, which is why the output below, run with a warm repository,
shows no Downloading lines. A build that must not touch the network can be run offline (-o), and a team can put a repository
manager in front of Central; both are covered on
Repositories, Mirrors & Repository Managers.
The old goal archetype:create, still found in books, does not exist any more. On Maven 3.10.0 it fails with
Could not find goal 'create' in plugin org.apache.maven.plugins:maven-archetype-plugin:3.4.1 among available goals crawl, create-from-project, generate, help, integration-test, jar, update-local-catalog.
Archetypes, their catalogues and how to write one are in
Archetypes.
Source: Maven Quickstart Archetype
What was generated
The command created a directory with the artifact id as its name. Its contents, from find . -type f | sort:
./.mvn/jvm.config
./.mvn/maven.config
./pom.xml
./src/main/java/com/mycompany/app/App.java
./src/test/java/com/mycompany/app/AppTest.java
That is the standard layout described on the philosophy page: sources under src/main/java, tests under src/test/java, the POM at the
top. The two files under .mvn are new in the current quickstart archetype (the 5-minute guide’s tree, written for an older one, does not
show them) and both are empty in this release (wc -c reports 0 bytes). They are the places for project-wide JVM options
(jvm.config) and command-line arguments (maven.config) that Maven reads at start-up, and a .mvn directory also marks the root of
the project for Maven 4; see
Configuring Maven. Without a .mvn directory, Maven 4.0.0-rc-7 prints
Unable to find the root directory. Create a .mvn directory in the root directory or add the root="true" attribute on the root project's model
(seen in another run of this page’s experiments, on a POM with no .mvn), so keeping it is useful.
The two Java files are as small as the guide promises:
package com.mycompany.app;
/**
* Hello world!
*/
public class App {
public static void main(String[] args) {
System.out.println("Hello World!");
}
}
package com.mycompany.app;
import static org.junit.jupiter.api.Assertions.assertTrue;
import org.junit.jupiter.api.Test;
/**
* Unit test for simple App.
*/
public class AppTest {
/**
* Rigorous Test :-)
*/
@Test
public void shouldAnswerWithTrue() {
assertTrue(true);
}
}
The POM
The pom.xml is the project descriptor and the core of a Maven project: Maven is project-centric, and the POM is the basic unit of work.
This is the generated file; the pluginManagement section, which is long, is cut where marked ... and shown in full in the next
section:
<?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.mycompany.app</groupId>
<artifactId>my-app</artifactId>
<version>1.0-SNAPSHOT</version>
<name>my-app</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.release>17</maven.compiler.release>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.junit</groupId>
<artifactId>junit-bom</artifactId>
<version>5.11.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<scope>test</scope>
</dependency>
<!-- Optionally: parameterized tests support -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
...
</pluginManagement>
</build>
</project>
Element by element:
| Element | What it does here |
|---|---|
|
the root of every POM; the namespace and |
|
the version of the POM model itself ( |
|
the coordinates of this project; the primary artifact will be |
|
display name and project website, used by the generated site; the |
|
value placeholders available anywhere in the POM; here the source encoding and |
|
pins versions without adding dependencies; here it imports the JUnit bill of materials ( |
|
what the project needs; both JUnit entries are |
|
pins the version of every plugin the default lifecycle uses, so that the build does not depend on Maven’s built-in defaults |
The POM has no packaging element, so it is jar (the default). The meaning of every element, inheritance and the effective POM are the
subject of POM Fundamentals; the coordinates are explained on the
philosophy page.
The plugin versions the archetype pinned
The part of the generated POM that the guides do not show is the one that decides how the build behaves. Its pluginManagement pins nine
plugins, and each is older than what Maven 3.10.0 would pick on its own, which help:describe shows for the install phase of a jar
project (the second column is read from the POM, the third from the lifecycle that Maven 3.10.0 printed):
| Plugin | Pinned by the archetype | Default of Maven 3.10.0 |
|---|---|---|
maven-clean-plugin |
3.4.0 |
3.5.0 |
maven-resources-plugin |
3.3.1 |
3.5.0 |
maven-compiler-plugin |
3.13.0 |
3.16.0 |
maven-surefire-plugin |
3.3.0 |
3.6.0 |
maven-jar-plugin |
3.4.2 |
3.5.1 |
maven-install-plugin |
3.1.2 |
3.2.0 |
maven-deploy-plugin |
3.1.2 |
3.2.0 |
The other two pinned plugins (maven-site-plugin 3.12.1 and maven-project-info-reports-plugin 3.6.1) are used only by the site and have no
lifecycle default to compare with. Pinning is good practice, and the build below uses the pinned versions, but a project created from an
archetype starts with versions that were current when the archetype was released, and keeping them current is part of maintaining the
project (the versions plugin and the ways to see plugin updates are on
Plugins & Their Configuration).
Source: Maven in 5 Minutes: The POM
Compile, test, package
Change into the project directory (cd my-app) for everything that follows. The commands name a lifecycle phase.
mvn compile
mvn -B -ntp compile
[INFO] Scanning for projects...
[INFO] ----------------------< com.mycompany.app:my-app >----------------------
[INFO] Building my-app 1.0-SNAPSHOT
[INFO] from pom.xml
[INFO] --------------------------------[ jar ]---------------------------------
[INFO] --- resources:3.3.1:resources (default-resources) @ my-app ---
[INFO] skip non existing resourceDirectory <scratch>/my-app/src/main/resources
[INFO] --- compiler:3.13.0:compile (default-compile) @ my-app ---
[INFO] Recompiling the module because of changed source code.
[INFO] Compiling 1 source file with javac [debug release 17] to target/classes
[INFO] BUILD SUCCESS
[INFO] Total time: 1.500 s
(Blank [INFO] lines, the Loaded ... prefixes lines and the finish timestamp are left out here and below.) Read the lines
rather than the verdict: each --- plugin:version:goal (execution-id) @ project --- line is a plugin goal running, in order. compile is a
phase, and to reach it Maven ran the goals bound to every phase up to it that has one; for this project that is
resources:resources (nothing to copy, since there is no src/main/resources) and compiler:compile. The compiler line shows the
effect of the maven.compiler.release property: javac [debug release 17], JDK 26 compiling for Java 17. Classes went to target/classes
without the POM saying so.
mvn test
mvn -B -ntp test
[INFO] --- resources:3.3.1:resources (default-resources) @ my-app ---
[INFO] skip non existing resourceDirectory <scratch>/my-app/src/main/resources
[INFO] --- compiler:3.13.0:compile (default-compile) @ my-app ---
[INFO] Nothing to compile - all classes are up to date.
[INFO] --- resources:3.3.1:testResources (default-testResources) @ my-app ---
[INFO] skip non existing resourceDirectory <scratch>/my-app/src/test/resources
[INFO] --- compiler:3.13.0:testCompile (default-testCompile) @ my-app ---
[INFO] Recompiling the module because of changed source code.
[INFO] Compiling 1 source file with javac [debug release 17] to target/test-classes
[INFO] --- surefire:3.3.0:test (default-test) @ my-app ---
[INFO] Using auto detected provider org.apache.maven.surefire.junitplatform.JUnitPlatformProvider
[INFO] Running com.mycompany.app.AppTest
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.028 s -- in com.mycompany.app.AppTest
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO] BUILD SUCCESS
(The T E S T S banner lines are left out.) Because test comes after compile, Maven ran compile again first, and the compiler plugin
answered that all classes were up to date. Surefire found the JUnit 5 provider by itself ("auto detected") and ran AppTest: its default
inclusion patterns are **/Test*.java, **/*Test.java, **/*Tests.java and **/*TestCase.java, and the default exclusion is
**/*$* (nested classes), as help:describe of the plugin’s test goal reports. To compile the tests without running them, use the test-compile phase (run: it printed nothing
under -q and exited with status 0). Testing is the subject of
Testing with Surefire.
mvn package
mvn -B -ntp package
[INFO] --- jar:3.4.2:jar (default-jar) @ my-app ---
[INFO] Building jar: <scratch>/my-app/target/my-app-1.0-SNAPSHOT.jar
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO] BUILD SUCCESS
(Only the lines that differ from the test run are shown; the jar plugin’s goal is the new one.) The result is in target:
classes
generated-sources
generated-test-sources
maven-archiver
maven-status
my-app-1.0-SNAPSHOT.jar
surefire-reports
test-classes
Running the JAR
The 5-minute guide runs the result with java -cp, and it works as printed:
java -cp target/my-app-1.0-SNAPSHOT.jar com.mycompany.app.App
Hello World!
It needs -cp and the class name because the JAR is a plain library: its manifest has no Main-Class entry. The manifest
Maven wrote, and the contents of the JAR (unzip -l), are:
Manifest-Version: 1.0
Created-By: Maven JAR Plugin 3.4.2
Build-Jdk-Spec: 26
Length Date Time Name
--------- ---------- ----- ----
0 02-01-1980 00:00 META-INF/
81 02-01-1980 00:00 META-INF/MANIFEST.MF
0 02-01-1980 00:00 com/
0 02-01-1980 00:00 com/mycompany/
0 02-01-1980 00:00 com/mycompany/app/
0 02-01-1980 00:00 META-INF/maven/
0 02-01-1980 00:00 META-INF/maven/com.mycompany.app/
0 02-01-1980 00:00 META-INF/maven/com.mycompany.app/my-app/
549 02-01-1980 00:00 com/mycompany/app/App.class
3101 02-01-1980 00:00 META-INF/maven/com.mycompany.app/my-app/pom.xml
65 02-01-1980 00:00 META-INF/maven/com.mycompany.app/my-app/pom.properties
--------- -------
3796 11 files
Two details. The JAR carries the POM and a pom.properties file under META-INF/maven/<groupId>/<artifactId>, so every Maven artifact
describes itself; the properties file (also in target/maven-archiver) holds groupId, artifactId and version, which an application can read
with the standard Java API, a technique the Getting Started Guide shows. And every entry is dated 1980-02-01, because Maven 3.10.0 builds reproducibly by default
(its super POM sets project.build.outputTimestamp); the same project built with Maven 3.9.16 dated its entries with the build time (10-16-2026 12:46) because it does not set that
property. Making the JAR executable, with a Main-Class and its dependencies, is on
Packaging JARs, WARs & Manifests and
Uber JARs with Shade & Assembly.
Install into the local repository
mvn install copies the artifact into the local repository, so that other projects on the machine can depend on it. The default
repository is ~/.m2/repository; to leave that untouched, this run used a private one with -Dmaven.repo.local:
mvn -B -ntp -Dmaven.repo.local=<repo> install
[INFO] --- install:3.1.2:install (default-install) @ my-app ---
[INFO] Installing <scratch>/my-app/pom.xml to <repo>/com/mycompany/app/my-app/1.0-SNAPSHOT/my-app-1.0-SNAPSHOT.pom
[INFO] Installing <scratch>/my-app/target/my-app-1.0-SNAPSHOT.jar to <repo>/com/mycompany/app/my-app/1.0-SNAPSHOT/my-app-1.0-SNAPSHOT.jar
[INFO] BUILD SUCCESS
(The compile, test and package output before it is the same as above.) The files the install left are the POM and the JAR under a path
made of the group id (dots to slashes), the artifact id and the version, plus maven-metadata-local.xml files and a
_remote.repositories file recording where the artifact came from:
com/mycompany/app/my-app/1.0-SNAPSHOT/_remote.repositories
com/mycompany/app/my-app/1.0-SNAPSHOT/maven-metadata-local.xml
com/mycompany/app/my-app/1.0-SNAPSHOT/my-app-1.0-SNAPSHOT.jar
com/mycompany/app/my-app/1.0-SNAPSHOT/my-app-1.0-SNAPSHOT.pom
com/mycompany/app/my-app/maven-metadata-local.xml
Another project can now depend on com.mycompany.app:my-app:1.0-SNAPSHOT and Maven will find it there. The repository layout, and what changes when the artifact
is deployed to a remote repository instead, are on the
philosophy page
and in Install, Deploy & Distribution Management.
Phases, goals and the lifecycle
The first command of this page, archetype:generate, names a goal: a task of a plugin, written prefix:goal. The others, compile,
test and package, are phases: steps in a build lifecycle, which is an ordered sequence of phases. Naming a phase runs every
phase before it, in order, up to and including it. The guide lists those up to compile: validate, generate-sources, process-sources,
generate-resources, process-resources and compile. What each phase does depends on which goals are bound to it, and that depends on
the packaging. Maven can print the binding for the jar packaging of this very project:
mvn -B -ntp help:describe -Dcmd=install
[INFO] 'install' is a phase corresponding to this plugin:
org.apache.maven.plugins:maven-install-plugin:3.2.0:install
It is a part of the lifecycle for the POM packaging 'jar'. This lifecycle includes the following phases:
* validate: Not defined
* initialize: Not defined
* generate-sources: Not defined
* process-sources: Not defined
* generate-resources: Not defined
* process-resources: org.apache.maven.plugins:maven-resources-plugin:3.5.0:resources
* compile: org.apache.maven.plugins:maven-compiler-plugin:3.16.0:compile
* process-classes: Not defined
* generate-test-sources: Not defined
* process-test-sources: Not defined
* generate-test-resources: Not defined
* process-test-resources: org.apache.maven.plugins:maven-resources-plugin:3.5.0:testResources
* test-compile: org.apache.maven.plugins:maven-compiler-plugin:3.16.0:testCompile
* process-test-classes: Not defined
* test: org.apache.maven.plugins:maven-surefire-plugin:3.6.0:test
* prepare-package: Not defined
* package: org.apache.maven.plugins:maven-jar-plugin:3.5.1:jar
* pre-integration-test: Not defined
* integration-test: Not defined
* post-integration-test: Not defined
* verify: Not defined
* install: org.apache.maven.plugins:maven-install-plugin:3.2.0:install
* deploy: org.apache.maven.plugins:maven-deploy-plugin:3.2.0:deploy
(Run in my-app; the framing [INFO] lines are left out. It lists the Maven 3.10.0 defaults, not the versions the archetype pinned, which is why
the versions differ from the build output above.) This is the whole build of a plain JAR project: eight goals bound to 23 phases, and the
other phases are hooks that a plugin may bind to. Two more lifecycles exist next to the default one listed: clean, which deletes the target
directory, and site, which generates documentation. Each phase and the choices behind them are explained on
Build Lifecycle.
Phases and goals can be mixed on one command line, and run in the order written. The guide’s example:
mvn -B -ntp clean dependency:copy-dependencies package
[INFO] --- clean:3.4.0:clean (default-clean) @ my-app ---
[INFO] --- dependency:3.11.0:copy-dependencies (default-cli) @ my-app ---
[INFO] --- resources:3.3.1:resources (default-resources) @ my-app ---
[INFO] --- compiler:3.13.0:compile (default-compile) @ my-app ---
[INFO] --- resources:3.3.1:testResources (default-testResources) @ my-app ---
[INFO] --- compiler:3.13.0:testCompile (default-testCompile) @ my-app ---
[INFO] --- surefire:3.3.0:test (default-test) @ my-app ---
[INFO] --- jar:3.4.2:jar (default-jar) @ my-app ---
[INFO] BUILD SUCCESS
(Filtered to the goal lines.) It cleaned the project, ran the dependency plugin’s copy-dependencies goal (Maven resolved the prefix to version 3.11.0,
because the POM does not manage that plugin), then ran the lifecycle up to package. The goal wrote the project’s dependencies to
target/dependency:
apiguardian-api-1.1.2.jar
junit-jupiter-api-5.11.0.jar
junit-jupiter-params-5.11.0.jar
junit-platform-commons-1.11.0.jar
opentest4j-1.3.0.jar
Those are the two direct test dependencies and their transitive dependencies, resolved from the versions in junit-bom. Note the identifier in the
output: (default-cli) is the execution id Maven gives to a goal invoked from the command line, and (default-<goal>) is the id of an execution bound by the
packaging. Plugin executions and how to bind another goal to a phase are on
Plugins & Their Configuration.
Source: Maven in 5 Minutes: Maven Phases
The site
A POM with a name, a URL and a few dependencies already carries enough information to generate a project web site:
mvn -B -ntp site
[INFO] --- site:3.12.1:site (default-site) @ my-app ---
[INFO] configuring report plugin org.apache.maven.plugins:maven-project-info-reports-plugin:3.6.1
[INFO] 15 reports detected for maven-project-info-reports-plugin:3.6.1: ci-management, dependencies, dependency-info, dependency-management, distribution-management, index, issue-management, licenses, mailing-lists, modules, plugin-management, plugins, scm, summary, team
[INFO] Rendering site with default locale English (en)
[INFO] Rendering content with org.apache.maven.skins:maven-default-skin:jar:1.3 skin.
[INFO] Generating "Dependencies" report --- maven-project-info-reports-plugin:3.6.1:dependencies
[INFO] Generating "Maven Coordinates" report --- maven-project-info-reports-plugin:3.6.1:dependency-info
[INFO] Generating "Dependency Management" report --- maven-project-info-reports-plugin:3.6.1:dependency-management
[INFO] Generating "About" report --- maven-project-info-reports-plugin:3.6.1:index
[INFO] Generating "Plugin Management" report --- maven-project-info-reports-plugin:3.6.1:plugin-management
[INFO] Generating "Plugins" report --- maven-project-info-reports-plugin:3.6.1:plugins
[INFO] Generating "Summary" report --- maven-project-info-reports-plugin:3.6.1:summary
[INFO] BUILD SUCCESS
(Filtered; the run took about five seconds.) Fifteen reports are available to the project-info plugin and seven were generated; the other eight (CI management, distribution management,
issue management, licenses, mailing lists, modules, SCM and team) were not, and this POM declares no issue tracker, mailing list, SCM or license. The result is under
target/site:
css
dependencies.html
dependency-info.html
dependency-management.html
images
index.html
plugin-management.html
plugins.html
project-info.html
summary.html
Customising the site, choosing skins and adding reports are on
Site & Reporting. Maven 3.10 also introduced the property
maven.site.lifecycle.disabled, covered with the other 3.10 changes in
Versions & Release History. To start from a ready-made site
skeleton, the guide suggests archetype:generate with maven-archetype-site (not run here).
The questions of the 30-minute guide
The Getting Started Guide is organised as a list of questions. The ones about compiling, testing, packaging, installing and the site are answered above. These are the rest, each checked against current Maven.
What is a SNAPSHOT version?
A version ending in -SNAPSHOT (the 1.0-SNAPSHOT of the generated POM) is the development version that comes before the release: the latest code
along a development branch, with no guarantee that it is stable or unchanging. A release version (no suffix) never changes. Releasing turns
1.0-SNAPSHOT into 1.0 and moves development to 1.1-SNAPSHOT. The point that matters in practice is what Maven does with them: it looks for
snapshot dependencies in the remote repositories again and downloads them again when they are newer than the local copy, and a snapshot that is
deployed is stored with a timestamp, as the philosophy page shows by deploying my-app to a local file: repository (the file becomes
my-app-1.0-20261016.104005-1.jar in the directory 1.0-SNAPSHOT, while a local install keeps the -SNAPSHOT name). The rules for resolving, ordering and
ranges of versions are on
Versions, Snapshots & Ranges.
How do I use plugins?
To customise a build you add or reconfigure a plugin in the build section of the POM. A plugin looks like a dependency (group id,
artifact id, version) and is downloaded the same way. The configuration element passes parameters to every goal of the plugin, and the
plugin’s documentation lists the parameters of each goal. The guide’s example configures the compiler for JDK 5 sources with <source>1.5</source>
and <target>1.5</target> on plugin 3.3; that no longer works, because current JDKs reject such old values. The modern way to say which
Java to compile for is the property the generated POM already has, maven.compiler.release, which was used in the compile run above
(javac [debug release 17]). The compiler’s other options, and toolchains for building with a JDK different from the one running Maven, are on
Compiling & Toolchains.
How do I add resources to my JAR?
Put them in src/main/resources: the files and directories there are copied to the root of the JAR with the same structure; test resources go in
src/test/resources and onto the test class path. No POM change is needed. By default nothing is changed in the copy; to substitute build
values into a resource, turn on filtering for the directory. The guide’s recipe, run on a copy of my-app with this
src/main/resources/META-INF/application.properties:
application.name=${project.name}
application.version=${project.version}
java.version=${java.version}
command.line.prop=${command.line.prop}
and <filtering>true</filtering> on the resource directory (the resources element must name the directory explicitly once it is overridden):
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
...
</build>
mvn -B -ntp process-resources "-Dcommand.line.prop=hello again"
cat target/classes/META-INF/application.properties
[INFO] --- resources:3.3.1:resources (default-resources) @ my-app ---
[INFO] Copying 1 resource from src/main/resources to target/classes
[INFO] BUILD SUCCESS
application.name=my-app
application.version=1.0-SNAPSHOT
java.version=26
command.line.prop=hello again
Maven filled project.name and project.version from the POM, java.version from the JVM’s system properties and command.line.prop from
the -D option. A property that is defined nowhere is left as it is: the same run without the -D option printed
command.line.prop=${command.line.prop}. Filter files (src/main/filters), the escape rules and the pitfalls (binary files that get corrupted by
filtering) are on Resources & Filtering.
How do I use external dependencies?
A dependency is declared in dependencies with at least a group id, an artifact id and a version (the version can come from dependencyManagement, as
the JUnit ones do here) and a scope that says how it is used: compile (the default), test, runtime and others. Maven looks in the local
repository first and downloads what is missing from the remote repositories, by default Maven Central. To find the coordinates of a library, look at its
page on Maven Central; the directory of an artifact there holds a maven-metadata.xml listing its versions. The copy-dependencies run above
shows the result for junit-jupiter-api: the artifact and its transitive dependencies. The guide’s example adds log4j:log4j:1.2.12. Do not
copy it: Log4j 1.x reached end of life on 5 August 2015, and its own site lists unfixed vulnerabilities (CVE-2019-17571, CVE-2021-4104 and others) and tells
users to upgrade to Log4j 2. The same section’s junit:junit:4.11 is also long superseded; a new project uses JUnit 5 (junit-jupiter) or later, as the
archetype does. Scopes, transitive resolution and conflicts are on
Dependencies, Scopes & Mediation. The other tools declare
the same dependency as an Ivy dependency element (Ant) or an implementation entry (Gradle); the mapping is on
Dependency Management Fundamentals.
Source: Apache Log4j 1.x: End of Life
How do I deploy my JAR to a remote repository?
Deployment needs two things in two places: the repository URL in the POM’s distributionManagement, and the credentials in the user’s
settings.xml, matched by the repository id. The guide shows an scp:// URL with a user name and a private key; that is a legacy transport.
Today the targets are an HTTPS repository manager or Maven Central, and credentials come from the environment or an encrypted settings.xml entry,
never from the POM. A deployment to a real server was not run here. What was run is the same goal against a local file: repository, which shows
the layout a remote repository would receive, on the philosophy page. The rest is in
Install, Deploy & Distribution Management,
settings.xml & Password Encryption and
Publishing to Maven Central.
How do I build more than one project at once?
Create a parent POM with pom packaging that lists the projects as modules, and run Maven on the parent. The tidepool scenario of this section is such a
build: a parent POM io.tidepool:tidepool-parent:1.0.0 with the modules tidepool-model, tidepool-engine and tidepool-cli. A single command at
the top builds all of them in dependency order:
mvn -B -ntp package
[INFO] Reactor Summary for tidepool parent 1.0.0:
[INFO]
[INFO] tidepool parent .................................... SUCCESS [ 0.000 s]
[INFO] tidepool model ..................................... SUCCESS [ 0.956 s]
[INFO] tidepool engine .................................... SUCCESS [ 0.104 s]
[INFO] tidepool cli ....................................... SUCCESS [ 0.011 s]
[INFO] BUILD SUCCESS
(The Reactor Summary, the last block of a multi-module build; the module builds before it have the same form as the single-project output above.) The mechanism is the reactor, covered with the glossary on the philosophy page and in full on Multi-Module Builds & the Reactor; inheritance from the parent is on Inheritance, Aggregation & the Effective POM.
The same project on Maven 3.9.16 and 4.0.0-rc-7
The generated project is not specific to one Maven. archetype:generate with the same command on 3.9.16 and on 4.0.0-rc-7 produced a src tree
and a pom.xml identical to the 3.10.0 one (verified with diff; both used the archetype plugin 3.4.1), and mvn package on each printed the same
goal lines with the same plugin versions (resources:3.3.1, compiler:3.13.0, surefire:3.3.0, jar:3.4.2), the same
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0 and BUILD SUCCESS, and, for 4.0.0-rc-7, no warning because the project has a .mvn directory.
What differs is the platform around the command, not the result: 3.10.0 and 4.0.0-rc-7 print the archetype catalogue warning described
above and 3.9.16 does not, and Maven 4.0.0-rc-7 itself is a release candidate (see
Maven 4: What’s New).
The Ant and Gradle equivalents of this page are not a template command in the same sense: Ant has no generator, so a project starts from a copied
build.xml (see Build File Structure), and Gradle has the gradle init task
(see Java Projects); neither was run for this page.
Where the official guides are outdated
Every command of "Maven in 5 Minutes" ran as printed. What has aged is the sample output and a few surrounding statements:
-
The sample output shows plugin versions of 2018 to 2020 (
maven-resources-plugin:3.0.2,maven-compiler-plugin:3.8.0,maven-surefire-plugin:2.22.1,maven-jar-plugin:3.0.2,maven-install-plugin:2.5.2) and a Maven 3.6.3--versionon Java 1.8. Current builds print the versions in the tables above, and the line format has changed (--- compiler:3.13.0:compilewithout themaven-prefix and[ jar ]banners). -
The sample POM is described as an 18-line file; the generated POM is more than 80 lines because it now pins plugin versions and imports a BOM.
-
The Getting Started Guide sections use
junit:junit:4.11(JUnit 4),log4j:log4j:1.2.12(end of life, above) and<source>1.5</source>(rejected by current JDKs). -
The "Java 9 or later" section is about the
maven.compiler.releaseproperty; since 3.6.0 of the compiler plugin that property is the way, and the generated POM already uses it. -
The guide’s deploy example uses
scp://and a private key insettings.xml; use HTTPS and encrypted or environment-provided credentials. -
Apache Maven 2 Effective Implementation uses
archetype:create, which is gone (shown above).
The versions to use today are in Versions & Release History.
Where to go next
-
Running Maven for every command-line option used above and the ones that were not.
-
POM Fundamentals for the elements of the generated POM.
-
Build Lifecycle for the phase list and the default bindings.
-
Dependencies, Scopes & Mediation for the
dependenciessection. -
Maven Wrapper to pin the Maven version per project.