Reducing the Slug Size of Java Applications
Last updated September 17, 2024
Table of Contents
When deploying with Git, it’s common for very large Java applications to exceed the slug size limits of the platform. If this happens, you’ll see an error like this when you deploy:
remote: -----> Compressing...
remote: ! Compiled slug size 583.3MB is too large, max is 500 MB.
There are a number of ways to mitigate this problem. In this article, you’ll learn how to configure your application to reduce it’s slug size.
Using the Maven Clean plugin to remove build artifacts
The Maven Clean plugin can be configured to remove non-essential artifacts after the build is complete. For example, if your application is packaged into a WAR file, and you would like remove all JAR files (because they are duplicated inside the WAR file), then you could configure the plugin like this in your pom.xml
:
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<id>clean-jar-artifacts</id>
<phase>install</phase>
<goals><goal>clean</goal></goals>
<configuration>
<excludeDefaultDirectories>true</excludeDefaultDirectories>
<filesets>
<fileset>
<directory>target/dependency/*.jar</directory>
</fileset>
</filesets>
</configuration>
</execution>
</executions>
</plugin>
This removes all target/dependency/*.jar
files from the slug after the install
phase.
Other common patterns for the <configuration>
element include removing everything in the target/
directory except the WAR file:
<fileset>
<directory>target</directory>
<excludes>
<exclude>*.war</exclude>
</excludes>
</fileset>
Or removing Node.js dependencies that were only needed to precompile JavaScript assets:
<fileset>
<directory>node_modules</directory>
</fileset>
<fileset>
<directory>.heroku/node</directory>
</fileset>
This configuration is particularly common when the Java buildpack is combined with the Node.js buildpack to perform JavaScript optimization during the build.
Using doLast in Gradle
For Gradle deployments, you can create a stage
task with a doLast
directive similar to this:
task stage {
dependsOn build
doLast {
delete fileTree(dir: "build", exclude: "libs")
delete fileTree(dir: "build/libs", exclude: "*.jar")
}
}
The files you remove will depend on your application.
Excluding test dependencies
If you are using the maven-dependency-plugin
to copy JAR files into the slug at build time, you may want to exclude your test dependencies. You can do this by setting the <includeScope>
value in the plugin’s configuration:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.4</version>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>package</phase>
<goals><goal>copy-dependencies</goal></goals>
<configuration>
<includeScope>compile</includeScope>
</configuration>
</execution>
</executions>
</plugin>
The included scopes defaults to test
, which includes your test dependencies, so compile
will actually exclude them.
Adding a .slugignore
file
If your Git repository includes binaries or other large files that are not needed at runtime, you can exclude them from the slug by creating a .slugignore
file in the root of your Git repo.
It is very common for the Git repository to include large files that are only needed when running tests. In this case, the .slugignore
file might look like this:
*.psd
*.pdf
/test
You can inspect the extracted contents of your slug by running heroku run bash
and using commands such as ls
and du
. This may help you identify large files that need to be added to the .slugignore
file. Exactly what should be excluded depends on the needs of each application.
If you implement these suggestions, and still have a slug that is too large, please contact Heroku support.