How to Shrink Spring Boot JARs by Extracting Dependencies and Config Files with Maven
This guide tackles the problem of oversized Spring Boot JARs by showing how to separate library JARs and configuration files from the main artifact, presenting three Maven‑based solutions—spring‑boot‑maven‑plugin, maven‑jar‑plugin, and maven‑assembly‑plugin—complete with configuration snippets, build commands, and deployment tips.
When publishing a Spring Boot application in production, the default packaging process creates a single executable JAR that contains all compiled classes, all dependency JARs, and configuration files. Even a tiny code change forces a full rebuild and upload of a large file, slowing down the development cycle.
The proposed solution is to decouple the third‑party libraries (the lib folder) and configuration resources (the config folder) from the core application JAR, so that only the lightweight core needs to be redeployed.
Method 1 – Using spring-boot-maven-plugin
Step 1: Exclude configuration files from the main JAR and place them in config
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<includes>
<include>**/*.properties</include>
<include>**/*.yml</include>
<include>**/*.xml</include>
<include>mapper/*.xml</include>
</includes>
<targetPath>${project.build.directory}/config</targetPath>
</resource>
</resources>Step 2: Build an executable JAR while excluding dependency JARs
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<jvmArguments>-Dfile.encoding=UTF-8</jvmArguments>
<layout>ZIP</layout>
<includes>
<include>no-exists-jar</include> <!-- placeholder to skip all deps -->
</includes>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>Step 3: Copy runtime dependencies to lib
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/lib</outputDirectory>
<includeScope>runtime</includeScope>
<excludeTransitive>false</excludeTransitive>
</configuration>
</execution>
</executions>
</plugin>After packaging, the directory layout looks like:
Run the application with the external libraries loaded:
java -jar -Dloader.path=./lib -jar xxx.jarSpring Boot automatically reads configuration files from the config directory, so you do not need to specify -Dspring.config.location explicitly.
Method 2 – Using maven-jar-plugin (and maven-resources-plugin )
Step 1: Package configuration files into config
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<configuration>
<encoding>UTF-8</encoding>
</configuration>
<executions>
<execution>
<id>copy-config</id>
<phase>package</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/twin-web/config</outputDirectory>
<resources>
<resource>
<directory>src/main/resources</directory>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>Step 2: Build an executable JAR without the dependencies
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<outputDirectory>${project.build.directory}/twin-web/</outputDirectory>
<archive>
<addMavenDescriptor>false</addMavenDescriptor>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>./libs/</classpathPrefix>
<mainClass>com.keqing.twinweb.TwinWebApplication</mainClass>
</manifest>
<manifestEntries>
<Class-Path>./config/</Class-Path>
</manifestEntries>
</archive>
<excludes>
<exclude>*.yml</exclude>
<exclude>mapper/**</exclude>
<exclude>*.xml</exclude>
</excludes>
</configuration>
</plugin>Step 3: Copy runtime libraries to libs
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/twin-web/libs</outputDirectory>
<includeScope>runtime</includeScope>
</configuration>
</execution>
</executions>
</plugin>Resulting package structure (illustrated in the image below) shows separate config, lib, and the core JAR.
Start the application with:
java -jar xxx.jarMethod 3 – Using maven-assembly-plugin
Step 1: Declare the assembly plugin
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<appendAssemblyId>false</appendAssemblyId>
<descriptors>
<descriptor>assembly.xml</descriptor>
</descriptors>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>Step 2: Create assembly.xml to define what goes where
<assembly>
<id>make-assembly</id>
<formats>
<format>tar.gz</format>
<format>zip</format>
</formats>
<includeBaseDirectory>true</includeBaseDirectory>
<fileSets>
<fileSet>
<directory>${basedir}/bin</directory>
<outputDirectory>/</outputDirectory>
<fileMode>0755</fileMode>
<includes>
<include>**.sh</include>
<include>**.bat</include>
</includes>
</fileSet>
<fileSet>
<directory>${basedir}/src/main/resources</directory>
<outputDirectory>config</outputDirectory>
<fileMode>0644</fileMode>
<includes>
<include>*.properties</include>
<include>*.yml</include>
<include>*.xml</include>
<include>mapper/*.xml</include>
</includes>
</fileSet>
<fileSet>
<directory>${project.build.directory}</directory>
<outputDirectory>/</outputDirectory>
<includes>
<include>*.jar</include>
</includes>
</fileSet>
</fileSets>
<dependencySets>
<dependencySet>
<useProjectArtifact>true</useProjectArtifact>
<outputDirectory>lib</outputDirectory>
<scope>runtime</scope>
<unpack>false</unpack>
</dependencySet>
</dependencySets>
</assembly>After running mvn package, the generated .zip or .tar.gz contains the core JAR, the config directory, and a lib folder with all runtime dependencies. The application can be started with the same loader path command:
java -jar -Dloader.path=./lib -jar xxx.jarAll three approaches achieve the same goal: a lean executable JAR that loads external libraries and configuration at runtime, dramatically reducing upload size and speeding up deployment cycles.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Architect
Professional architect sharing high‑quality architecture insights. Topics include high‑availability, high‑performance, high‑stability architectures, big data, machine learning, Java, system and distributed architecture, AI, and practical large‑scale architecture case studies. Open to ideas‑driven architects who enjoy sharing and learning.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
