Sapan Diwakar

Software developer

Follow me on Twitter Check out my code on GitHub View some of my designs on Dribbble Take a look at my Linked In profile

[How to] Reducing Heroku Slug Size

Once a slug size reaches 300 MB, Heroku will warn about larger slug sizes having the potential to cause longer boot times. The best practice is to keep slug sizes as small as possible for fast deploys and other operations.

Warning: You slug size (400 MB) exceeds our soft limit (300 MB) which may affect boot time

What is a slug

Slugs are compressed and pre-packaged copies of your application optimized for distribution to the dyno manager. When you git push to Heroku, your code is received by the slug compiler which transforms your repository into a slug. Scaling an application then downloads and expands the slug to a dyno for execution.

The steps that heroku takes once you push some code to git are:

  1. Checkout HEAD from the master branch.
  2. Remove all files specified in .slugignore.
  3. Download, build and install local dependencies as specified in your build file (for example, Gemfile, package.json, requirements.txt, pom.xml, etc.) with the dependency management tool supported by the language (e.g. Bundler, npm, pip, Maven).
  4. Package the filesystem as a slug archive.

Reducing Slug Size

There are a few steps that can be followed to reduce the slug size.

Purge build cache

Buildpacks cache some content to speed up future builds. But sometimes, when your dependencies change (especially when you remove a dependency), it might not be removed from the cache. So if you are facing unexpectedly high slug sizes and you have removed some dependencies from your project, try this first (if you can live with a slow build on the next deploy).

$ heroku plugins:install heroku-repo
$ heroku repo:purge_cache -a appname

Ignore files with .slugignore

Your .sligignore should list directories and files that are in the repo (not ignored by .gitignore) but not needed for the app to run on prod. Some examples of files like these are the tests, documentation and design files. To remove these from the slug, create a .slugignore at the root of the project.

*.psd
/doc
/test

To check out what files are being put into the slug, you can also enter the heroku bash and check the filesystem.

heroku run bash -a appname  
du -sh .[^.]* * | sort -hr  

Node modules

This part is specific to apps that include an asset pipeline that bundles all JavaScript code to single script. If you are using a node server, this might not apply to you.

If you are using Rails with webpacker, you might have a lot of dependencies in node_modules. But after the asset pipeline compiles the resources, you probably don't need the node_modules directory (unless you run custom node scripts at runtime that use those modules). To remove the node_modules directory in this case, we can use the heroku-buildpack-post-build-clean buildpack with a .slug-post-clean file. The format of this file is the same as .gitignore or .sligignore, so just list out directories that you want to ignore from the final slug and they will be removed. One thing to make sure with the buildpack is that this should be the last one in the order otherwise it will remove the files before your actual buildpack runs.

But what if you are using custom node scripts that access the node_modules at runtime? In that case, what we do is move those scripts to a separate directory with it's own package.json file. To install the dependencies into that directory along with the installation of root package.json, add a postinstall script to your root package.json. This will instruct yarn to change directory to your custom script and install dependencies there after the dependencies of your root project are installed.

"scripts": {
  "postinstall": "yarn --cwd lib/custom-node-script"
}

With this, you can then safely remove your root node_modules directory even when using custom node scripts in a production Rails app.