Guide to Working with Manifests
The archive-producing plugins (jar, war, ejb, ear and others) build the manifest of their archive with Maven Archiver. You adjust it in the archive element of the plugin configuration, see Guide to Configuring Archive Plugins. The examples below use maven-jar-plugin, but they work in every plugin that uses Maven Archiver. The Maven Archiver reference lists every archive and manifest parameter.
Default Manifest
Without any configuration the manifest contains these entries:
Manifest-Version: 1.0
Created-By: Maven JAR Plugin 3.5.1
Java-Version: 17
Build-Jdk-Spec: 21
Created-Bynames the plugin that built the archive, with its version.Java-Versionis therelease(or elsetarget) ofmaven-compiler-plugin, such as themaven.compiler.releaseproperty. It is left out when neither is set.Build-Jdk-Specis the specification version of the JDK running Maven, here 21. It does not take toolchains into account.
Set <addDefaultEntries>false</addDefaultEntries> in <manifest> to leave out Created-By, Java-Version and Build-Jdk-Spec.
Adding Implementation And Specification Details
Implementation and specification entries are not added by default. Ask for them in the manifest element:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.5.1</version>
<configuration>
<archive>
<manifest>
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
<addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
</manifest>
</archive>
</configuration>
</plugin>
For a project named Demo, version 1.2.3, whose <organization> is named Acme, the manifest gets these entries on top of the default ones:
Specification-Title: Demo
Specification-Version: 1.2
Specification-Vendor: Acme
Implementation-Title: Demo
Implementation-Version: 1.2.3
Implementation-Vendor: Acme
Specification-Version is the major and minor version of the project. If the POM has no <organization>/<name>, the two Vendor entries are left out.
To record the build environment, add <addBuildEnvironmentEntries>true</addBuildEnvironmentEntries> to <manifest>. It adds Build-Tool (the Maven version), Build-Jdk (JDK version and vendor) and Build-Os (operating system name, version and architecture). Those values differ between machines, so they make a reproducible build harder to achieve.
Manifest Entries
If the other options do not cover what you need, add your own entries with <manifestEntries>. Values can be literals or POM expressions:
<project>
<url>http://some.url.org/</url>
...
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.5.1</version>
<configuration>
<archive>
<manifestEntries>
<mode>development</mode>
<url>${project.url}</url>
</manifestEntries>
</archive>
</configuration>
</plugin>
</plugins>
</build>
</project>
The manifest then contains:
mode: development
url: http://some.url.org/
If the POM has no <url>, the expression cannot be resolved and the url entry is left out.
Manifest Sections
<manifestSections> adds named sections to the manifest. Each <manifestSection> has a <name> and its own <manifestEntries>:
<archive>
<manifestSections>
<manifestSection>
<name>foo</name>
<manifestEntries>
<id>nice foo</id>
</manifestEntries>
</manifestSection>
<manifestSection>
<name>bar</name>
<manifestEntries>
<id>nice bar</id>
</manifestEntries>
</manifestSection>
</manifestSections>
</archive>
Each section follows the main section after a blank line:
Name: foo
id: nice foo
Name: bar
id: nice bar
Using Your Own Manifest File
To start from a hand-written manifest, point <manifestFile> at it:
<archive>
<manifestFile>src/main/resources/META-INF/MANIFEST.MF</manifestFile>
</archive>
The entries of your file are merged with the ones Maven Archiver creates, and an entry in your file overrides the generated one with the same name.
Setting Up the Classpath
The examples in this section assume a project with these dependencies:
<dependencies>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.1</version>
</dependency>
<dependency>
<groupId>org.codehaus.plexus</groupId>
<artifactId>plexus-utils</artifactId>
<version>1.1</version>
</dependency>
</dependencies>
The manifest excerpts show only the entries that the example adds. In the file itself, lines are wrapped at 72 bytes.
Adding a Class-Path Entry
<addClasspath> adds the runtime dependencies of the project to the manifest:
<archive>
<manifest>
<addClasspath>true</addClasspath>
</manifest>
</archive>
Class-Path: commons-lang-2.1.jar plexus-utils-1.1.jar
Making the Jar Executable
An executable jar also needs the main class, set with <mainClass>:
<archive>
<manifest>
<addClasspath>true</addClasspath>
<mainClass>fully.qualified.MainClass</mainClass>
</manifest>
</archive>
Class-Path: commons-lang-2.1.jar plexus-utils-1.1.jar
Main-Class: fully.qualified.MainClass
Defining a Classpath Directory Prefix
When the dependencies live in a directory next to the archive, for example in a skinny war, add a <classpathPrefix>:
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
</manifest>
</archive>
Class-Path: lib/commons-lang-2.1.jar lib/plexus-utils-1.1.jar
Using a Maven Repository-Style Classpath
If the archive holds a Maven repository-style directory tree, set <classpathLayoutType> to repository:
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
<classpathLayoutType>repository</classpathLayoutType>
</manifest>
</archive>
Class-Path: lib/commons-lang/commons-lang/2.1/commons-lang-2.1.jar lib/org/codehaus/plexus/plexus-utils/1.1/plexus-utils-1.1.jar
Using a Custom Classpath Format
For any other layout, set <classpathLayoutType> to custom and describe the layout in <customClasspathLayout>:
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathLayoutType>custom</classpathLayoutType>
<customClasspathLayout>WEB-INF/lib/${artifact.groupIdPath}/${artifact.artifactId}-${artifact.version}${dashClassifier?}.${artifact.extension}</customClasspathLayout>
</manifest>
</archive>
Class-Path: WEB-INF/lib/commons-lang/commons-lang-2.1.jar WEB-INF/lib/org/codehaus/plexus/plexus-utils-1.1.jar
Maven Archiver resolves each expression in the layout like this:
- If present, it trims the prefix
artifact.from the expression. - It tries the expression as a property of the artifact (
artifactIdcallsgetArtifactId()). - It tries the expression as a property of the artifact's
ArtifactHandler(extensioncallsgetExtension()). - It tries the expression as a key of a special set of properties:
dashClassifier:-followed by the classifier if the artifact has one, otherwise an empty string.dashClassifier?: a synonym ofdashClassifier.groupIdPath: the group ID with each.replaced by/.
Handling Snapshot Versions
By default, a snapshot dependency appears in the Class-Path with its timestamped version, such as foo-1.0-20260101.120000-1.jar. Which name your archive actually contains depends on how you assemble it. For example, the Assembly Plugin decides this in the <outputFileNameMapping> of a <dependencySet>.
To use the -SNAPSHOT name with the simple or repository layout, disable <useUniqueVersions>:
<archive>
<manifest>
<addClasspath>true</addClasspath>
<useUniqueVersions>false</useUniqueVersions>
</manifest>
</archive>
With the custom layout, use ${artifact.baseVersion} instead of ${artifact.version}:
<customClasspathLayout>WEB-INF/lib/${artifact.groupIdPath}/${artifact.artifactId}-${artifact.baseVersion}${dashClassifier?}.${artifact.extension}</customClasspathLayout>

