Reducing the Slug Size of Play Framework Applications
Last updated December 03, 2024
Table of Contents
When deploying with Git, it’s common for very large Play applications to exceed the slug size limits of the platform. If this happens, you’ll see an error like this when you deploy:
remote: ! Compiled slug size 583.3MB is too large, max is 500 MB.
There are a number of ways to mitigate this problem, including switching to non-Git deployment. In this article, you’ll learn how to do this and how to configure your application to reduce it’s slug size.
This article is only applicable to apps that use classic buildpacks.
Using sbt-native-packager
The sbt-native-packager plugin allows the buildpack to prune the sbt cache before compiling the slug. It is a replacement for the deprecated sbt-start-script plugin, and is already used in the most recent versions of the Play framework. To use sbt-native-packager with Play, you’ll need to upgrade to version 2.2 or 2.3 or Play and the plugin will be included for you. Then change your Procfile
to contain something like this:
web: target/universal/stage/bin/my-app -Dhttp.port=${PORT}
You may also need to include -DapplyEvolutions.default=true
in the command, depending on your application.
For standalone applications, add the following to your project/plugins.sbt
:
addSbtPlugin("com.typesafe.sbt" % "sbt-native-packager" % "0.8.0-RC2")
And add this to your build.sbt
:
import NativePackagerKeys._
Now when you run sbt stage
, the plugin will package everything that’s needed to run your application in the target/universal/stage
directory. This allows the buildpack to remove any other temporary assets from the slug.
Renaming the web
target
Play packages web assets in to the target/web
directory. The buildpack does not remove these by default, but you can configure your application such that buildpack knows it’s ok to remove them. To do so, add the following to your build.sbt
:
WebKeys.webTarget := target.value / "scala-web"
artifactPath in PlayKeys.playPackageAssets := WebKeys.webTarget.value / (artifactPath in PlayKeys.playPackageAssets).value.getName
This renames the web
target directory to scala-web
and moves the assets artifact into that directory. In this way, the buildpack can safely remove the assets from the slug.
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.
Using sbt to clean build artifacts
This method is useful when your build creates large artifacts that are not required at runtime, or if your project contains large files that are needed at compile time but not at runtime.
Add the following code to your build.sbt
file:
val stage = taskKey[Unit]("Stage and clean task")
stage := {
(stage in Universal).value
if (sys.env.getOrElse("POST_STAGE_CLEAN", "false").equals("true")) {
println("cleaning...")
sbt.IO.delete(baseDirectory.value / "my-subdir")
}
}
This will override the default stage
task provided by the sbt-native-packager plugin, and add some new behavior. The first line in the body of the custom stage
task invokes the original stage
task from sbt-native-packager (stage in Universal
). Then it checks for a POST_STAGE_CLEAN
config var, which prevents sbt from deleting your project locally. If that config var is set to true
, then the rest of the task can delete project files.
Once the code above has been added to your Git repo, you will need to set the following config var:
$ heroku config:set POST_STAGE_CLEAN="true"
When you push to Heroku, it will ran the staging task and clean your project accordingly.
If you implement these suggestions, and still have a slug that is too large, please contact Heroku support.