Deploy a Spring Boot app

Deploy a Spring Boot app on Hangar with Maven or Gradle and no Dockerfile, connect it to PostgreSQL and tune the JVM to the service's memory.

Updated

A Spring Boot app deploys on Hangar from its repository, built with Maven or Gradle into a jar and run as a long-lived JVM. No Dockerfile is needed.

Before you start

  • A Spring Boot project in a Git repository, with pom.xml and the Maven wrapper, or build.gradle and gradlew, at the root.
  • A Hangar account.

1. Create the service

Create a project, add a service and pick your repository and branch. Choose a region and leave the builder on Automatic. It detects Maven or Gradle, builds the project with JDK 21 and starts the jar with java -jar, passing PORT to Spring as server.port.

To build with another JDK, set it in the Variables tab:

RAILPACK_JDK_VERSION=17

2. Set the variables

The start command reads PORT, which Hangar sets to the domain's container port. Add your own configuration in the Variables tab:

JAVA_OPTS=-XX:MaxRAMPercentage=75

JAVA_OPTS is passed to the JVM. MaxRAMPercentage sizes the heap from the service's memory limit, leaving room for the rest of the JVM, instead of the JVM's conservative default.

3. Deploy and add a domain

Deploy the service. In Settings → Networking, add a domain with container port 8080 and HTTPS on.

Spring Boot sits behind Hangar's proxy, which terminates HTTPS. So that redirects and generated links use https://, add to application.properties:

server.forward-headers-strategy=framework

Adding PostgreSQL

Add a PostgreSQL service in the same project and region. From its internal connection details, set on the app:

SPRING_DATASOURCE_URL=jdbc:postgresql://<host>:5432/<database>
SPRING_DATASOURCE_USERNAME=<user>
SPRING_DATASOURCE_PASSWORD=<password>

Spring Boot maps these variables to spring.datasource.* on its own. JDBC URLs do not take the postgresql://user:password@ form, which is why the credentials go in their own variables.

Flyway or Liquibase migrations run when the app starts, before it accepts traffic, as they do locally.

Health checks

With Spring Boot Actuator on the classpath, /actuator/health reports when the app is ready. The service's health check, in Settings → Scaling, is a command run inside the container, so it can call that endpoint if the image has a client for it:

curl -fs http://localhost:8080/actuator/health

Give it a start period long enough for the JVM to boot, such as 60 seconds, so a new deployment only takes traffic once Spring has started.

Troubleshooting

  • 502 on the domain: a PORT variable you set differs from the container port. Remove it, or make the two match.
  • The container is killed with exit code 137: the JVM uses more memory than the service's limit. Lower MaxRAMPercentage or raise the limit.
  • Redirects go to http://: server.forward-headers-strategy is missing.

Frequently asked questions

Can I deploy Spring Boot on Hangar without a Dockerfile?
Yes. The automatic builder detects Maven or Gradle, builds the jar with JDK 21 by default and starts it with java -jar, passing the PORT variable, which Hangar sets to the domain's container port, as server.port.
How do I choose the Java version?
Set the RAILPACK_JDK_VERSION variable, for example to 17. Without it the builder uses JDK 21.
How do I connect Spring Boot to a Hangar PostgreSQL database?
Set SPRING_DATASOURCE_URL to the database's host, port and name in JDBC form, and SPRING_DATASOURCE_USERNAME and SPRING_DATASOURCE_PASSWORD to its credentials. Spring Boot reads them without any change to application.properties.

Deploy your app on Hangar

Connect a repository and it is live in minutes.

Start deploying