Railway

Deploy Spring Boot | Java 25 API in a Two-Stage Container

Spring Boot 4 on Java 25, two-stage image, bound to the platform port

Deploy Spring Boot | Java 25 API in a Two-Stage Container

Deploy and Host a Spring Boot API on Railway

Spring Boot 4 on Java 25, in a two-stage container, listening on the port the platform assigns.

About Hosting Spring Boot

The Spring Boot template on Railway builds from a repository last updated in October 2024, and about four deployments in ten never come up. Two things in it are worth fixing.

The port is never configured. Its application.properties contains a single line - the application name. Spring then listens on its own default rather than on the port the platform hands the container, and whether that works is left to autodetection. Here the properties file says server.port=${PORT:8080}.

The container is a single stage. Its Dockerfile builds with a full JDK and then runs that same image, so the deployed container carries the JDK, the Maven cache and the sources. This one builds in a Maven image and copies only the jar into a JRE image - 347 MB, with nothing in it that only the build needed.

Common Use Cases

  • A JSON API with the Spring ecosystem behind it - data, security, messaging
  • A service that has to run on the JVM because the rest of the stack does
  • A starting point where the container, port and health check are already right

Dependencies for Spring Boot Hosting

  • Nothing. One service, no database. Add spring-boot-starter-data-jpa and a Postgres service when you need persistence.

Deployment Dependencies

Implementation Details

MethodPathDoes
GET/Lists the endpoints
GET/actuator/healthReports UP once the application context is ready
GET/greet?name=worldGreets, 400 when the parameter is missing

Four decisions worth keeping if you rewrite this:

  • Dependencies resolve before the sources are copied. pom.xml goes into the image first and dependency:go-offline runs against it alone, so editing a .java file rebuilds in seconds rather than re-downloading every dependency.
  • -XX:MaxRAMPercentage=75. Left alone the JVM sizes its heap from the host machine memory, not the container limit, and gets killed for allocating past it.
  • Graceful shutdown is on. The platform sends SIGTERM before replacing a container; without server.shutdown=graceful in-flight requests are dropped on every deploy.
  • Actuator exposes only health, without details. The detailed view reports disk paths and component internals to anyone who can reach the domain.

Why Deploy Spring Boot on Railway?

A JVM service with a domain, TLS and a health check from one deploy, and an image small enough that a redeploy is not a coffee break.


Template Content

More templates in this category

View Template
open-excalidraw
Self-hostable collaborative drawing built on Excalidraw

Prateek Mohanty
1
View Template
caring-vibrancy
Deploy and Host caring-vibrancy with Railway

5
View Template
Flask WebSocket Chat
Single file, realtime multi-user websocket chat using flask-socketio

Clement Ochieng
3