Deploying Java Applications with the Heroku Maven Plugin
Last updated February 06, 2023
Table of Contents
In addition to Git deployment, Heroku supports building and releasing apps via an API. The Heroku Maven plugin utilizes this API to provide direct deployment of prepackaged standalone web applications to Heroku.
This may be a preferred approach for applications that take a long time to compile, or that need to be deployed from a Continuous Integration server such as Travis CI or Jenkins.
In this article, you’ll learn how to include the Heroku Maven Plugin in your project, configure it, and deploy your application to Heroku.
Adding the plugin
To include the plugin in your project, add the following to your pom.xml
file:
<project>
...
<build>
...
<plugins>
<plugin>
<groupId>com.heroku.sdk</groupId>
<artifactId>heroku-maven-plugin</artifactId>
<version>3.0.7</version>
</plugin>
</plugins>
</build>
</project>
Then create a new Heroku application by running:
$ heroku create
If your application is under version control with Git, then the plugin will detect the application name by default. If you are not using Git, you must add this configuration to the plugin (but replace the app name with the name of your app):
<configuration>
<appName>sushi</appName>
</configuration>
If your application is packaged as a WAR file, then this configuration is sufficient, but if your application is a standalone Java application then you’ll need to define a process type.
A process type is a command used to start your application. You can configure these with a Procfile
as describe in the Process Types and the Procfile article. Or you can configure them directly in your pom.xml
like this:
<configuration>
...
<processTypes>
<web>java $JAVA_OPTS -cp target/classes:target/dependency/* Main</web>
</processTypes>
</configuration>
The configuration above tells Heroku to start a web process using the Main
class. Your process type will differ depending on your application code.
Now you’re ready to deploy.
Deploying with the plugin
If your application is packaged as a WAR, then you can create the slug and deploy it to Heroku with the following command:
$ mvn clean heroku:deploy-war
...
[INFO] -----> Packaging application...
[INFO] - app: obscure-sierra-7788
[INFO] - including: ./target/dependency/webapp-runner.jar
[INFO] - including: ./target/my-app.war
[INFO] -----> Creating build...
[INFO] - file: target/heroku/slug.tgz
[INFO] - size: 1MB
[INFO] -----> Uploading build...
[INFO] - success
[INFO] -----> Deploying...
[INFO] remote:
[INFO] remote: -----> Fetching custom tar buildpack... done
[INFO] remote: -----> JVM Common app detected
[INFO] remote: -----> Installing OpenJDK 1.8... done
[INFO] remote: -----> Discovering process types
[INFO] remote: Procfile declares types -> web
[INFO] remote:
[INFO] remote: -----> Compressing... done, 49.5MB
[INFO] remote: -----> Launching... done, v157
[INFO] remote: https://obscure-sierra-7788.herokuapp.com/ deployed to Heroku
[INFO] remote:
[INFO] -----> Done
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 01:04 min
[INFO] Finished at: 2014-11-11T16:07:11-06:00
[INFO] Final Memory: 20M/304M
[INFO] ------------------------------------------------------------------------
If your application is standalone (and thus required a process type), you can deploy with this command:
$ mvn clean heroku:deploy
...
[INFO] -----> Packaging application...
[INFO] - app: obscure-sierra-7788
[INFO] - including: ./target/
[INFO] -----> Creating build...
[INFO] - file: target/heroku/slug.tgz
[INFO] - size: 1MB
[INFO] -----> Uploading build...
[INFO] - success
[INFO] -----> Deploying...
[INFO] remote:
[INFO] remote: -----> Fetching custom tar buildpack... done
[INFO] remote: -----> JVM Common app detected
[INFO] remote: -----> Installing OpenJDK 1.8... done
[INFO] remote: -----> Discovering process types
[INFO] remote: Procfile declares types -> web
[INFO] remote:
[INFO] remote: -----> Compressing... done, 49.5MB
[INFO] remote: -----> Launching... done, v157
[INFO] remote: https://obscure-sierra-7788.herokuapp.com/ deployed to Heroku
[INFO] remote:
[INFO] -----> Done
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 01:04 min
[INFO] Finished at: 2014-11-11T16:07:11-06:00
[INFO] Final Memory: 20M/304M
[INFO] ------------------------------------------------------------------------
Now you can visit your application with this command:
$ heroku open
Or view the logs with this command:
$ heroku logs
The Heroku CLI will allow you to access the application, and run commands just like an application deployed with git push
.
Advanced configuration
The Maven plugin allows for several advanced configuration settings. All of these settings are defined in the <configuration>
element for the plugin in the pom.xml
file. For example, you may set the desired JDK version like so:
<jdkVersion>1.8</jdkVersion>
For valid values and the current default version, see Heroku’s Java support.
You can set configuration variables:
<configVars>
<MY_VAR>SomeValue</MY_VAR>
<JAVA_OPTS>-Xss512k -XX:+UseCompressedOops</JAVA_OPTS>
</configVars>
Be aware that any variable defined in <configVars>
will override defaults, or previously defined config vars.
You can also include additional directories in the slug like this (note that they must be relative to the project root):
<includes>
<include>etc/readme.txt</include>
</includes>
By default, the plugin will package the essential directories under your project’s target
directory, so including additional directories should not be necessary in most cases.
You can specify an alternate location for your WAR file like this:
<warFile>relative/path/myapp.war</warFile>
But this is only accepted when deploying with the heroku:deploy-war
goal.
Deploying to multiple applications
Most real applications will be required to deploy to multiple Heroku apps (such as dev, test, and prod). Normally this is done with multiple Git remotes. But with the plugin you can use either system properties, environment variables, or any other native Maven/Java configuration method. For example, you might define your heroku.appName
as a system property like this:
$ mvn heroku:deploy -Dheroku.appName=myapp
However, the preferred approach uses Maven profiles. An example configuration might look like this:
<build>
<plugins>
<plugin>
<groupId>com.heroku.sdk</groupId>
<artifactId>heroku-maven-plugin</artifactId>
<configuration>
<processTypes>
<web>java $JAVA_OPTS -cp target/classes:target/dependency/* Main</web>
</processTypes>
</configuration>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>test</id>
<build>
<plugins>
<plugin>
<groupId>com.heroku.sdk</groupId>
<artifactId>heroku-maven-plugin</artifactId>
<configuration>
<appName>myapp-test</appName>
</configuration>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>prod</id>
<build>
<plugins>
<plugin>
<groupId>com.heroku.sdk</groupId>
<artifactId>heroku-maven-plugin</artifactId>
<configuration>
<appName>myapp-prod</appName>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
For more information on the plugin and Java deployment in general, see Heroku’s Java support. For more information on Maven, see the Apache Maven documentation.