Packaging Executable Archives

The plugin can create executable archives (jar files and war files) that contain all of an application’s dependencies and can then be run with java -jar.

Packaging an executable archive is performed by the repackage goal, as shown in the following example:

<build>
	<plugins>
		<plugin>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-maven-plugin</artifactId>
			<executions>
				<execution>
					<goals>
						<goal>repackage</goal>
					</goals>
				</execution>
			</executions>
		</plugin>
	</plugins>
</build>
The repackage goal is not meant to be used alone on the command-line as it operates on the source jar (or war) produced by the package phase. To use this goal on the command-line, you must include the package phase: mvn package spring-boot:repackage.
If you are using spring-boot-starter-parent, such execution is already pre-configured with a repackage execution ID so that only the plugin definition should be added.

The example above repackages a jar or war archive that is built during the package phase of the Maven lifecycle, including any provided dependencies that are defined in the project. If some of these dependencies need to be excluded, you can use one of the exclude options; see the dependency exclusion for more details.

The original (that is non-executable) artifact is renamed to .original by default but it is also possible to keep the original artifact using a custom classifier.

The outputFileNameMapping feature of the maven-war-plugin is currently not supported.

The spring-boot-devtools and spring-boot-docker-compose modules are automatically excluded by default (you can control this using the excludeDevtools and excludeDockerCompose properties). In order to make that work with war packaging, the spring-boot-devtools and spring-boot-docker-compose dependencies must be set as optional or with the provided scope.

The plugin rewrites your manifest, and in particular it manages the Main-Class and Start-Class entries. If the defaults don’t work you have to configure the values in the Spring Boot plugin, not in the jar plugin. The Main-Class in the manifest is controlled by the layout property of the Spring Boot plugin, as shown in the following example:

<build>
	<plugins>
		<plugin>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-maven-plugin</artifactId>
			<configuration>
				<mainClass>${start.class}</mainClass>
				<layout>ZIP</layout>
			</configuration>
			<executions>
				<execution>
					<goals>
						<goal>repackage</goal>
					</goals>
				</execution>
			</executions>
		</plugin>
	</plugins>
</build>

The layout property defaults to a value determined by the archive type (jar or war). The following layouts are available:

  • JAR: regular executable JAR layout.

  • WAR: executable WAR layout. provided dependencies are placed in WEB-INF/lib-provided to avoid any clash when the war is deployed in a servlet container.

  • ZIP (alias to DIR): similar to the JAR layout using PropertiesLauncher.

  • NONE: Bundle all dependencies and project resources. Does not bundle a bootstrap loader.

Layered Jar or War

A repackaged jar contains the application’s classes and dependencies in BOOT-INF/classes and BOOT-INF/lib respectively. Similarly, an executable war contains the application’s classes in WEB-INF/classes and dependencies in WEB-INF/lib and WEB-INF/lib-provided. For cases where a docker image needs to be built from the contents of a jar or war, it’s useful to be able to separate these directories further so that they can be written into distinct layers.

Layered archives use the same layout as a regular repackaged jar or war, but include an additional meta-data file that describes each layer.

By default, the following layers are defined:

  • dependencies for any dependency whose version does not contain SNAPSHOT.

  • spring-boot-loader for the loader classes.

  • snapshot-dependencies for any dependency whose version contains SNAPSHOT.

  • application for local module dependencies, application classes, and resources.

Module dependencies are identified by looking at all of the modules that are part of the current build. If a module dependency can only be resolved because it has been installed into Maven’s local cache and it is not part of the current build, it will be identified as regular dependency.

The layers order is important as it determines how likely previous layers can be cached when part of the application changes. The default order is dependencies, spring-boot-loader, snapshot-dependencies, application. Content that is least likely to change should be added first, followed by layers that are more likely to change.

The repackaged archive includes the layers.idx file by default. To disable this feature, you can do so in the following manner:

<project>
	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
				<configuration>
					<layers>
						<enabled>false</enabled>
					</layers>
				</configuration>
			</plugin>
		</plugins>
	</build>
</project>

Custom Layers Configuration

Depending on your application, you may want to tune how layers are created and add new ones. This can be done using a separate configuration file that should be registered as shown below:

<project>
	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
				<configuration>
					<layers>
						<enabled>true</enabled>
						<configuration>${project.basedir}/src/layers.xml</configuration>
					</layers>
				</configuration>
			</plugin>
		</plugins>
	</build>
</project>

The configuration file describes how an archive can be separated into layers, and the order of those layers. The following example shows how the default ordering described above can be defined explicitly:

<layers xmlns="http://www.springframework.org/schema/boot/layers"
		xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
		xsi:schemaLocation="http://www.springframework.org/schema/boot/layers
	                      https://www.springframework.org/schema/boot/layers/layers-3.4.xsd">
	<application>
		<into layer="spring-boot-loader">
			<include>org/springframework/boot/loader/**</include>
		</into>
		<into layer="application" />
	</application>
	<dependencies>
		<into layer="application">
			<includeModuleDependencies />
		</into>
		<into layer="snapshot-dependencies">
			<include>*:*:*SNAPSHOT</include>
		</into>
		<into layer="dependencies" />
	</dependencies>
	<layerOrder>
		<layer>dependencies</layer>
		<layer>spring-boot-loader</layer>
		<layer>snapshot-dependencies</layer>
		<layer>application</layer>
	</layerOrder>
</layers>

The layers XML format is defined in three sections:

  • The <application> block defines how the application classes and resources should be layered.

  • The <dependencies> block defines how dependencies should be layered.

  • The <layerOrder> block defines the order that the layers should be written.

Nested <into> blocks are used within <application> and <dependencies> sections to claim content for a layer. The blocks are evaluated in the order that they are defined, from top to bottom. Any content not claimed by an earlier block remains available for subsequent blocks to consider.

The <into> block claims content using nested <include> and <exclude> elements. The <application> section uses Ant-style path matching for include/exclude expressions. The <dependencies> section uses group:artifact[:version] patterns. It also provides <includeModuleDependencies /> and <excludeModuleDependencies /> elements that can be used to include or exclude local module dependencies.

If no <include> is defined, then all content (not claimed by an earlier block) is considered.

If no <exclude> is defined, then no exclusions are applied.

Looking at the <dependencies> example above, we can see that the first <into> will claim all module dependencies for the application.layer. The next <into> will claim all SNAPSHOT dependencies for the snapshot-dependencies layer. The final <into> will claim anything left (in this case, any dependency that is not a SNAPSHOT) for the dependencies layer.

The <application> block has similar rules. First claiming org/springframework/boot/loader/** content for the spring-boot-loader layer. Then claiming any remaining classes and resources for the application layer.

The order that <into> blocks are defined is often different from the order that the layers are written. For this reason the <layerOrder> element must always be included and must cover all layers referenced by the <into> blocks.

spring-boot:repackage

org.springframework.boot:spring-boot-maven-plugin:3.4.1

Repackage existing JAR and WAR archives so that they can be executed from the command line using java -jar. With layout=NONE can also be used simply to package a JAR with nested dependencies (and no main class, so not executable).

Required parameters

Name Type Default

outputDirectory

File

${project.build.directory}

Optional parameters

Name Type Default

attach

boolean

true

classifier

String

embeddedLaunchScript

File

embeddedLaunchScriptProperties

Properties

excludeDevtools

boolean

true

excludeDockerCompose

boolean

true

excludeGroupIds

String

excludes

List

executable

boolean

false

includeSystemScope

boolean

false

includeTools

boolean

true

includes

List

layers

Layers

layout

LayoutType

layoutFactory

LayoutFactory

loaderImplementation

LoaderImplementation

mainClass

String

outputTimestamp

String

${project.build.outputTimestamp}

requiresUnpack

List

skip

boolean

false

Parameter details

attach

Attach the repackaged archive to be installed into your local Maven repository or deployed to a remote repository. If no classifier has been configured, it will replace the normal jar. If a classifier has been configured such that the normal jar and the repackaged jar are different, it will be attached alongside the normal jar. When the property is set to false, the repackaged archive will not be installed or deployed.

Name

attach

Type

boolean

Default value

true

User property

Since

1.4.0

classifier

Classifier to add to the repackaged archive. If not given, the main artifact will be replaced by the repackaged archive. If given, the classifier will also be used to determine the source archive to repackage: if an artifact with that classifier already exists, it will be used as source and replaced. If no such artifact exists, the main artifact will be used as source and the repackaged archive will be attached as a supplemental artifact with that classifier. Attaching the artifact allows to deploy it alongside to the original one, see the Maven documentation for more details.

Name

classifier

Type

java.lang.String

Default value

User property

Since

1.0.0

embeddedLaunchScript

The embedded launch script to prepend to the front of the jar if it is fully executable. If not specified the 'Spring Boot' default script will be used.

Name

embeddedLaunchScript

Type

java.io.File

Default value

User property

Since

1.3.0

embeddedLaunchScriptProperties

Properties that should be expanded in the embedded launch script.

Name

embeddedLaunchScriptProperties

Type

java.util.Properties

Default value

User property

Since

1.3.0

excludeDevtools

Exclude Spring Boot devtools from the repackaged archive.

Name

excludeDevtools

Type

boolean

Default value

true

User property

spring-boot.repackage.excludeDevtools

Since

1.3.0

excludeDockerCompose

Exclude Spring Boot dev services from the repackaged archive.

Name

excludeDockerCompose

Type

boolean

Default value

true

User property

spring-boot.repackage.excludeDockerCompose

Since

3.1.0

excludeGroupIds

Comma separated list of groupId names to exclude (exact match).

Name

excludeGroupIds

Type

java.lang.String

Default value

User property

spring-boot.excludeGroupIds

Since

1.1.0

excludes

Collection of artifact definitions to exclude. The Exclude element defines mandatory groupId and artifactId components and an optional classifier component. When configured as a property, values should be comma-separated with colon-separated components: groupId:artifactId,groupId:artifactId:classifier

Name

excludes

Type

java.util.List

Default value

User property

spring-boot.excludes

Since

1.1.0

executable

Make a fully executable jar for *nix machines by prepending a launch script to the jar. <p> Currently, some tools do not accept this format so you may not always be able to use this technique. For example, jar -xf may silently fail to extract a jar or war that has been made fully-executable. It is recommended that you only enable this option if you intend to execute it directly, rather than running it with java -jar or deploying it to a servlet container.

Name

executable

Type

boolean

Default value

false

User property

Since

1.3.0

includeSystemScope

Include system scoped dependencies.

Name

includeSystemScope

Type

boolean

Default value

false

User property

Since

1.4.0

includeTools

Include JAR tools.

Name

includeTools

Type

boolean

Default value

true

User property

Since

3.3.0

includes

Collection of artifact definitions to include. The Include element defines mandatory groupId and artifactId components and an optional classifier component. When configured as a property, values should be comma-separated with colon-separated components: groupId:artifactId,groupId:artifactId:classifier

Name

includes

Type

java.util.List

Default value

User property

spring-boot.includes

Since

1.2.0

layers

Layer configuration with options to disable layer creation, exclude layer tools jar, and provide a custom layers configuration file.

Name

layers

Type

org.springframework.boot.maven.Layers

Default value

User property

Since

2.3.0

layout

The type of archive (which corresponds to how the dependencies are laid out inside it). Possible values are JAR, WAR, ZIP, DIR, NONE. Defaults to a guess based on the archive type.

Name

layout

Type

org.springframework.boot.maven.AbstractPackagerMojo$LayoutType

Default value

User property

spring-boot.repackage.layout

Since

1.0.0

layoutFactory

The layout factory that will be used to create the executable archive if no explicit layout is set. Alternative layouts implementations can be provided by 3rd parties.

Name

layoutFactory

Type

org.springframework.boot.loader.tools.LayoutFactory

Default value

User property

Since

1.5.0

loaderImplementation

The loader implementation that should be used.

Name

loaderImplementation

Type

org.springframework.boot.loader.tools.LoaderImplementation

Default value

User property

Since

3.2.0

mainClass

The name of the main class. If not specified the first compiled class found that contains a main method will be used.

Name

mainClass

Type

java.lang.String

Default value

User property

Since

1.0.0

outputDirectory

Directory containing the generated archive.

Name

outputDirectory

Type

java.io.File

Default value

${project.build.directory}

User property

Since

1.0.0

outputTimestamp

Timestamp for reproducible output archive entries, either formatted as ISO 8601 (yyyy-MM-dd’T’HH:mm:ssXXX) or an int representing seconds since the epoch.

Name

outputTimestamp

Type

java.lang.String

Default value

${project.build.outputTimestamp}

User property

Since

2.3.0

requiresUnpack

A list of the libraries that must be unpacked from uber jars in order to run. Specify each library as a <dependency> with a <groupId> and a <artifactId> and they will be unpacked at runtime.

Name

requiresUnpack

Type

java.util.List

Default value

User property

Since

1.1.0

skip

Skip the execution.

Name

skip

Type

boolean

Default value

false

User property

spring-boot.repackage.skip

Since

1.2.0

Examples

Custom Classifier

By default, the repackage goal replaces the original artifact with the repackaged one. That is a sane behavior for modules that represent an application but if your module is used as a dependency of another module, you need to provide a classifier for the repackaged one. The reason for that is that application classes are packaged in BOOT-INF/classes so that the dependent module cannot load a repackaged jar’s classes.

If that is the case or if you prefer to keep the original artifact and attach the repackaged one with a different classifier, configure the plugin as shown in the following example:

<project>
	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
				<executions>
					<execution>
						<id>repackage</id>
						<goals>
							<goal>repackage</goal>
						</goals>
						<configuration>
							<classifier>exec</classifier>
						</configuration>
					</execution>
				</executions>
			</plugin>
		</plugins>
	</build>
</project>

If you are using spring-boot-starter-parent, the repackage goal is executed automatically in an execution with id repackage. In that setup, only the configuration should be specified, as shown in the following example:

<project>
	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
				<executions>
					<execution>
						<id>repackage</id>
						<configuration>
							<classifier>exec</classifier>
						</configuration>
					</execution>
				</executions>
			</plugin>
		</plugins>
	</build>
</project>

This configuration will generate two artifacts: the original one and the repackaged counter part produced by the repackage goal. Both will be installed/deployed transparently.

You can also use the same configuration if you want to repackage a secondary artifact the same way the main artifact is replaced. The following configuration installs/deploys a single task classified artifact with the repackaged application:

<project>
	<build>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-jar-plugin</artifactId>
				<executions>
					<execution>
						<goals>
							<goal>jar</goal>
						</goals>
						<phase>package</phase>
						<configuration>
							<classifier>task</classifier>
						</configuration>
					</execution>
				</executions>
			</plugin>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
				<executions>
					<execution>
						<id>repackage</id>
						<goals>
							<goal>repackage</goal>
						</goals>
						<configuration>
							<classifier>task</classifier>
						</configuration>
					</execution>
				</executions>
			</plugin>
		</plugins>
	</build>
</project>

As both the maven-jar-plugin and the spring-boot-maven-plugin runs at the same phase, it is important that the jar plugin is defined first (so that it runs before the repackage goal). Again, if you are using spring-boot-starter-parent, this can be simplified as follows:

<project>
	<build>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-jar-plugin</artifactId>
				<executions>
					<execution>
						<id>default-jar</id>
						<configuration>
							<classifier>task</classifier>
						</configuration>
					</execution>
				</executions>
			</plugin>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
				<executions>
					<execution>
						<id>repackage</id>
						<configuration>
							<classifier>task</classifier>
						</configuration>
					</execution>
				</executions>
			</plugin>
		</plugins>
	</build>
</project>

Custom Name

If you need the repackaged jar to have a different local name than the one defined by the artifactId attribute of the project, use the standard finalName, as shown in the following example:

<project>
	<build>
		<finalName>my-app</finalName>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
				<executions>
					<execution>
						<id>repackage</id>
						<goals>
							<goal>repackage</goal>
						</goals>
					</execution>
				</executions>
			</plugin>
		</plugins>
	</build>
</project>

This configuration will generate the repackaged artifact in target/my-app.jar.

Local Repackaged Artifact

By default, the repackage goal replaces the original artifact with the executable one. If you need to only deploy the original jar and yet be able to run your app with the regular file name, configure the plugin as follows:

<project>
	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
				<executions>
					<execution>
						<id>repackage</id>
						<goals>
							<goal>repackage</goal>
						</goals>
						<configuration>
							<attach>false</attach>
						</configuration>
					</execution>
				</executions>
			</plugin>
		</plugins>
	</build>
</project>

This configuration generates two artifacts: the original one and the executable counter part produced by the repackage goal. Only the original one will be installed/deployed.

Custom Layout

Spring Boot repackages the jar file for this project using a custom layout factory defined in the additional jar file, provided as a dependency to the build plugin:

<project>
	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
				<executions>
					<execution>
						<id>repackage</id>
						<goals>
							<goal>repackage</goal>
						</goals>
						<configuration>
							<layoutFactory implementation="com.example.CustomLayoutFactory">
								<customProperty>value</customProperty>
							</layoutFactory>
						</configuration>
					</execution>
				</executions>
				<dependencies>
					<dependency>
						<groupId>com.example</groupId>
						<artifactId>custom-layout</artifactId>
						<version>0.0.1.BUILD-SNAPSHOT</version>
					</dependency>
				</dependencies>
			</plugin>
		</plugins>
	</build>
</project>

The layout factory is provided as an implementation of LayoutFactory (from spring-boot-loader-tools) explicitly specified in the pom. If there is only one custom LayoutFactory on the plugin classpath and it is listed in META-INF/spring.factories then it is unnecessary to explicitly set it in the plugin configuration.

Layout factories are always ignored if an explicit layout is set.

Dependency Exclusion

By default, both the repackage and the run goals will include any provided dependencies that are defined in the project. A Spring Boot project should consider provided dependencies as "container" dependencies that are required to run the application. Generally speaking, Spring Boot projects are not used as dependencies and are therefore unlikely to have any optional dependencies. When a project does have optional dependencies they too will be included by the repackage and run goals.

Some of these dependencies may not be required at all and should be excluded from the executable jar. For consistency, they should not be present either when running the application.

There are two ways one can exclude a dependency from being packaged/used at runtime:

  • Exclude a specific artifact identified by groupId and artifactId, optionally with a classifier if needed.

  • Exclude any artifact belonging to a given groupId.

The following example excludes com.example:module1, and only that artifact:

<project>
	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
				<configuration>
					<excludes>
						<exclude>
							<groupId>com.example</groupId>
							<artifactId>module1</artifactId>
						</exclude>
					</excludes>
				</configuration>
			</plugin>
		</plugins>
	</build>
</project>

This example excludes any artifact belonging to the com.example group:

<project>
	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
				<configuration>
					<excludeGroupIds>com.example</excludeGroupIds>
				</configuration>
			</plugin>
		</plugins>
	</build>
</project>

JAR Tools

When a layered jar or war is created, the spring-boot-jarmode-tools jar will be added as a dependency to your archive. With this jar on the classpath, you can launch your application in a special mode which allows the bootstrap code to run something entirely different from your application, for example, something that extracts the layers. If you wish to exclude this dependency, you can do so in the following manner:

<project>
	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
				<configuration>
					<includeTools>false</includeTools>
				</configuration>
			</plugin>
		</plugins>
	</build>
</project>

Custom Layers Configuration

The default setup splits dependencies into snapshot and non-snapshot, however, you may have more complex rules. For example, you may want to isolate company-specific dependencies of your project in a dedicated layer. The following layers.xml configuration shown one such setup:

<layers xmlns="http://www.springframework.org/schema/boot/layers"
		xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
		xsi:schemaLocation="http://www.springframework.org/schema/boot/layers
						  https://www.springframework.org/schema/boot/layers/layers-3.4.xsd">
	<application>
		<into layer="spring-boot-loader">
			<include>org/springframework/boot/loader/**</include>
		</into>
		<into layer="application" />
	</application>
	<dependencies>
		<into layer="snapshot-dependencies">
			<include>*:*:*SNAPSHOT</include>
		</into>
		<into layer="company-dependencies">
			<include>com.acme:*</include>
		</into>
		<into layer="dependencies"/>
	</dependencies>
	<layerOrder>
		<layer>dependencies</layer>
		<layer>spring-boot-loader</layer>
		<layer>snapshot-dependencies</layer>
		<layer>company-dependencies</layer>
		<layer>application</layer>
	</layerOrder>
</layers>

The configuration above creates an additional company-dependencies layer with all libraries with the com.acme groupId.