Heroku Clojure Support
Last updated May 09, 2024
Table of Contents
This document describes the general behavior of Heroku as it relates to the recognition and execution of Clojure applications. For a more detailed explanation of how to deploy an application, see:
Activation
Heroku’s Clojure support is applied only when the application has a
project.clj
file in the root directory.
Clojure applications that use Maven can be deployed as well, but they will be treated as Java applications, so different documentation will apply.
Configuration
Leiningen 1.7.1 will be used by default, but if you have
:min-lein-version "2.0.0"
in project.clj (highly recommended) then
the Leiningen 2.9.1 release will be used instead.
Your Procfile
should declare what process types make your app
run. Often in development Leiningen projects are launched using lein
run -m my.project.namespace
, but this is not recommended in
production because it leaves Leiningen running in addition to your
project’s process. It also uses profiles that are intended for
development, which can let test libraries and test configuration sneak
into production.
In order to ensure consistent builds, normally application config is not visible during compile time, with the exception of private repository credentials (LEIN_USERNAME
, etc) if present. In order to change what is exposed, set the BUILD_CONFIG_ALLOWLIST
config to a space-separated list of config var names. Note that this can result in unpredictable behavior since changing your app’s config does not result in a rebuild of your app.
Uberjar
If your project.clj
contains an :uberjar-name
setting, then
lein uberjar
will run during deploys. If you do this, your Procfile
entries should consist of just java
invocations.
If your main namespace doesn’t have a :gen-class
then you can use
clojure.main
as your entry point and indicate your app’s main
namespace using the -m
argument in your Procfile
:
web: java -cp target/myproject-standalone.jar clojure.main -m myproject.web
If you have custom settings you would like to only apply during build,
you can place them in an :uberjar
profile. This can be useful to use
AOT-compiled classes in production but not during development where
they can cause reloading issues:
:profiles {:uberjar {:main myproject.web, :aot :all}}
If you need Leiningen in a heroku run
session, it will be downloaded
on-demand.
Note that if you use Leiningen features which affect runtime like
:jvm-opts
, extraction of native dependencies, or :java-agents
,
then you’ll need to do a little extra work to ensure your Procfile’s
java
invocation includes these things. In these cases it might be
simpler to use Leiningen at runtime instead.
Customizing the build
You can customize the Leiningen build by setting the following configuration variables:
LEIN_BUILD_TASK
: the Leinigen command to run.LEIN_INCLUDE_IN_SLUG
: Set toyes
to add lein to uberjar slug.
Leiningen at runtime
Instead of putting a direct java
invocation into your Procfile, you
can have Leiningen handle launching your app. If you do this, be sure
to use the trampoline
and with-profile
tasks. Trampolining will
cause Leiningen to calculate the classpath and code to run for your
project, then exit and execute your project’s JVM, while
with-profile
will omit development profiles:
web: lein with-profile production trampoline run -m myapp.web
Including Leiningen in your slug will add about ten megabytes to its size and will add a second or two of overhead to your app’s boot time.
Overriding build behavior
If neither of these options get you quite what you need, you can check
in your own executable bin/build
script into your app’s repo and it
will be run instead of compile
or uberjar
after setting up Leiningen.
Setting the Leiningen version
The buildpack will check for a bin/lein
script in the repo, and if present will run it instead of the default lein
command. This allows you to control the exact version of Leiningen used to build the app.
Setting Clojure CLI version
You can customize the version of the Clojure CLI installed with your app by setting the CLOJURE_CLI_VERSION
config variable. The default version is 1.10.0.411.
Runtimes
Heroku makes a number of different runtimes available. You can configure your app to select a particular Clojure runtime, as well as the configure the JDK.
Supported JDK versions
Heroku currently uses OpenJDK 8 to run your application. OpenJDK version 7 is available. Depending on what major version you select the latest available update of that Java runtime will be used each time you deploy your app. For a list of current versions see the Java support article.
The JDK that your app uses will be included in the slug, which will affect your slug size.
Specifying a Java version
You can specify a Java version by adding a file called system.properties
to your application.
Set a property java.runtime.version
in the file:
java.runtime.version=1.8
1.8 is the default so if you’d like to use Java 8 you don’t need this file at all. You can specify JDK 7 by setting this property to “1.7”. For details on how to set specific update versions, see the Java support article.
Supported Clojure versions
Heroku supports apps on any production release of Clojure, running on a supported JDK version.
Add-ons
No add-ons are provisioned by default. If you need a SQL database for your app, add one explicitly. For example, to add an Essential-0 Heroku Postgres database:
$ heroku addons:create heroku-postgresql:essential-0