Heroku Java Support
Last updated October 22, 2024
Table of Contents
Heroku can run Java applications across a variety of Java implementations and includes support for framework-specific workflows.
This document describes the general behavior of Heroku as it relates to the recognition and execution of Java applications. General Java support on Heroku refers to the support for all frameworks except for Play. You can read about Play framework support in the Play framework support reference.
For framework-specific tutorials visit:
Activation
The default build system for Java applications on Heroku is Maven. Heroku Java support for Maven is applied to applications that contain a pom.xml
.
When a deployed application is recognized as a Java application, Heroku responds with Java app detected
.
$ git push heroku master
-----> Java app detected
Build Behavior
The following command is run to build your app:
$ mvn -B -DskipTests clean dependency:list install
However, if Heroku detects an mvnw
script in your application’s repository, it runs this script instead of the default Maven installation. You can override this behavior by explicitly setting a Maven version.
The maven repo is cached between builds to improve performance.
Environment
The following environment variables are set in dyno at boot-time:
PORT
: The web process binds to this HTTP portJAVA_HOME
: The location of the JDK install directoryLD_LIBRARY_PATH
: With the location of the JDK shared librariesJDBC_DATABASE_URL
: If aDATABASE_URL
variable is present, this variable is populated with the converted form. See Connecting to Relational Databases on Heroku with Java for more information.JAVA_TOOL_OPTIONS
: Default Java options based on dyno sizeJAVA_OPTS
: Default Java options based on dyno size (identical toJAVA_TOOL_OPTIONS
)
About JAVA_TOOL_OPTIONS
JAVA_TOOL_OPTIONS
is directly supported by Java and intended to augment a command line in environments where the command line can’t be accessed or modified. Heroku uses this value to set default Java options based on dyno size. Since Java automatically picks it up, you don’t need to include it in your Procfile
command.
You can override these settings in the Procfile
command, which takes precedence over the defaults. For example, to change the default of -Xmx300m
, you could pass in:
web: java -Xms150M -jar target/myapp.jar
You can also set your own JAVA_TOOL_OPTIONS
config var. Setting your own causes its value to be appended to Heroku’s defaults and take precedence. Individual options not overridden in the Procfile
command or custom JAVA_TOOL_OPTIONS
are still in effect.
When a Java process is started on your dyno, the following Java options are added to JAVA_TOOL_OPTIONS
and automatically picked up by Java:
-
-Dfile.encoding=UTF-8
-XX:+UseContainerSupport
(for Java 11 and higher)
Adjusting Environment for a Dyno Size
When a new dyno type is selected, the following settings are automatically added to JAVA_TOOL_OPTIONS
:
eco
,basic
, orstandard-1x
:-Xmx300m -Xss512k -XX:CICompilerCount=2
standard-2x
:-Xmx671m -XX:CICompilerCount=2
performance-m
:-Xmx2g
performance-l
:-Xmx12g
performance-l-ram
,performance-xl
,performance-2xl
:-XX:MaxRAMPercentage=80.0
For Private Space and Shield Private Space dynos, the values are:
private-s
orshield-s
:-Xmx671m -XX:CICompilerCount=2
private-m
orshield-m
:-Xmx2g
private-l
orshield-l
:-Xmx12g
private-l-ram
,private-xl
,private-2xl
,shield-l-ram
,shield-xl
,shield-2xl
:-XX:MaxRAMPercentage=80.0
Monitoring Resource Usage
You can use additional JVM flags to monitor resource usage in a dyno. The following flags are recommended for monitoring resource usage:
-XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintTenuringDistribution -XX:+UseConcMarkSweepGC
See the troubleshooting article for more information about tuning a JVM process.
Specifying a Java Version
We recommend to always explicitly configure the required OpenJDK major version for your application. If no version is configured, the default version for the stack will be installed. The default version will change over time and your application might fail to build with the new default version.
The current default versions for each stack are as follows:
heroku-20 |
heroku-22 |
heroku-24 |
---|---|---|
OpenJDK 8 | OpenJDK 8 | Latest LTS (currently OpenJDK 21) |
To explicitly configure the OpenJDK version, add a file called system.properties
to your application. Within that file,
set the java.runtime.version
property to the OpenJDK major version for your app:
java.runtime.version=11
Refer to the supported Java versions table for accepted major version values.
You can also pin your OpenJDK version to a full version. We don’t recommend this, unless there is a strong reason to do so. Pinning to a full version will cause your app to not automatically get OpenJDK security updates on each build.
To use a full version, set the java.runtime.version
property to the full version string:
java.runtime.version=1.8.0_412
Supported Java Versions
Refer to the table below for the latest available version for each OpenJDK major version and Heroku stack.
Rows marked up with red text and background indicate an OpenJDK version that is fully end-of-life and no longer receiving updates of any kind from the upstream maintainers and is no longer supported by Heroku.
OpenJDK Version | heroku-20 |
heroku-22 |
heroku-24 |
---|---|---|---|
OpenJDK 7 | 1.7.0_352 | 1.7.0_352 | - |
OpenJDK 8 | 1.8.0_432 | 1.8.0_432 | 1.8.0_432 |
OpenJDK 11 | 11.0.25 | 11.0.25 | 11.0.25 |
OpenJDK 13 | 13.0.14 | 13.0.14 | - |
OpenJDK 14 | 14.0.2 | - | - |
OpenJDK 15 | 15.0.10 | 15.0.10 | - |
OpenJDK 16 | 16.0.2 | - | - |
OpenJDK 17 | 17.0.13 | 17.0.13 | 17.0.13 |
OpenJDK 18 | 18.0.2.1 | 18.0.2.1 | - |
OpenJDK 19 | 19.0.2 | 19.0.2 | - |
OpenJDK 20 | 20.0.2 | 20.0.2 | - |
OpenJDK 21 | 21.0.5 | 21.0.5 | 21.0.5 |
OpenJDK 22 | 22.0.2 | 22.0.2 | 22.0.2 |
OpenJDK 23 | 23.0.1 | 23.0.1 | 23.0.1 |
The OpenJDK that your app uses is included in the slug, which affects your slug size.
Specifying an OpenJDK Distribution
Heroku supports builds of OpenJDK from either Azul® Zulu® or Heroku. Both distributions are built from the same source and are fully compliant with the Java SE specification. Azul® Zulu® builds of OpenJDK are also TCK/JCK certified and are our recommended OpenJDK distribution.
Current default distributions of OpenJDK for each stack are:
heroku-20 |
heroku-22 |
heroku-24 |
---|---|---|
Heroku | Azul® Zulu® | Azul® Zulu® |
Using a Non-default Distribution
To use a non-default distribution with your app, you must specify a Java version. Prefix the version string with either heroku-
or zulu-
to select the respective distribution.
To use OpenJDK 11 and explicitly select Azul® Zulu® as the OpenJDK distribution, add the following to system.properties
:
java.runtime.version=zulu-11
Upgrading your Java Version
All Java apps are automatically upgraded to the latest available OpenJDK version when and only when they’re deployed. They aren’t upgraded if the app isn’t redeployed or if a specific version is configured in the system.properties
file.
Specifying a Maven Version
Heroku supports the Maven Wrapper, which is the recommended mechanism for defining a Maven version. If Heroku detects an mvnw
file in the root directory of your repository, it uses this script to launch the Maven process.
You can also specify a Maven version with the system.properties
file by setting a maven.version
property like this:
maven.version=3.9.4
If this property is defined, the mvnw
script is ignored. You are not upgraded to a newer version automatically and need to update your system.properties
file to get a newer version.
The default, if you don’t specify a version and don’t use Maven Wrapper, is 3.9.4. This default will change over time and we recommend using Maven Wrapper to ensure stable builds.
Default Web Process Type
The Java buildpack automatically detects the use of the Spring Boot and Thorntail web frameworks. For Spring Boot, it creates a web
process type with the following command:
java -Dserver.port=$PORT $JAVA_OPTS -jar target/*.jar
For Thorntail, the buildpack uses this command for the default web
process type:
java -Dswarm.http.port=$PORT $JAVA_OPTS -jar target/*.jar
You can override these defaults or define a custom process type using a Procfile
. The appropriate command depends on your app and the frameworks in use. See one of the Java tutorials for information on setting up your Procfile
.
Postgres Auto-Provisioning
This section is only applicable to accounts created before May 15, 2023 or if you asked Heroku Support to enable auto-provisioning for your account.
A Heroku Postgres database automatically provisions on the first deploy of your Java applications. These apps must have a dependency on the Postgres JDBC driver or pgjdbc-ng driver in their pom.xml
. This auto-provisioning populates the DATABASE_URL
environment variable.
If you don’t want the Postgres add-on, remove it by running:
$ heroku addons:destroy DATABASE --app example-app