An open book whose pages are thin sheets of violet glass etched with circuits

Home

Guides

Java Deployment Guide: From a Local Build to a Running Production App

Every Java app takes the same six steps between your editor and a public URL. Here is what each step decides, and which guide covers it in depth.

Older search results for a Java deployment guide still point to documentation about applets and Java Web Start, two technologies that no longer ship with current JDKs. Deploying Java today means something else: you build an artifact, pick a runtime, wrap it in a container or hand it to a platform, and watch it through logs and health checks. This Java deployment guide walks through that path in order, so you know which decision belongs to which step before you open one of the hands-on guides.

Figures checked in November 2026.

The six steps of a Java deployment

The path is the same whether the app is a weekend project or a team service. Only the tools change.

Step What you decide Typical choice today
1. Build tool How the code is compiled and dependencies resolved Maven or Gradle, run through the project's wrapper
2. Packaging What artifact leaves the build Executable JAR with an embedded server, or a WAR
3. Runtime Which JDK runs it An OpenJDK build of Java 21 or 25
4. Container How the runtime and app travel together A Docker image based on a JRE image, or a platform buildpack
5. Host Where it runs and who patches the machine A container platform, a PaaS with a Java runtime, or a VM
6. Operations How you know it is alive Logs to stdout, an HTTP health endpoint, alerts

The first two steps happen on your machine or in CI. Steps three to five are where most deployment problems show up, usually as an app that starts fine locally and then runs out of memory on a 512 MB instance. Step six is the one people skip, and it is the reason a crashed app can sit unnoticed for a weekend.

Build tool and packaging: JAR or WAR

Maven and Gradle both produce either kind of artifact, so the decision that matters is packaging. An executable JAR (often called a fat JAR or uber JAR) contains your classes, every dependency and an embedded web server. Spring Boot builds this by default with Tomcat inside, and you start it with a single java -jar app.jar. Nothing else has to be installed on the target except a JDK.

A WAR is the older model. It holds the web application only, and an external servlet container such as Apache Tomcat, WildFly or Payara loads it. That model is still alive. Azure App Service offers built-in Tomcat and JBoss EAP stacks next to plain Java SE, and AWS Elastic Beanstalk has Tomcat platforms, the newest pairing Corretto 25 with Tomcat 11.0.27. If you join a team with an existing Tomcat farm, you will deploy WARs.

For anything new, the JAR is easier to reason about: one process, one port, one log stream. Choose the WAR when a shared container is already part of the setup, not because a tutorial from 2008 used one.

Runtime and container

The JDK you pick sets your security update window. Java 25 is the current LTS release, and free builds such as Eclipse Temurin are planned until at least September 2031. Java 21 builds from the same project run until at least December 2029. The vendor-by-vendor dates, including Oracle, Amazon Corretto, Azul, Microsoft and Red Hat, sit on the Java versions and support dates page, and the licensing differences between vendor builds are explained in the OpenJDK vs Oracle JDK comparison.

Containers solve a different problem: they freeze the runtime and the app together, so the image that passed your tests is the one that runs in production. A two-stage Dockerfile builds with a full JDK image and ships with a smaller JRE image. Platforms such as Heroku and Clever Cloud skip the Dockerfile and build from source with their own Java runtimes. Heroku's default on its current stacks is the latest LTS, OpenJDK 25.

Choosing a host

Hosts fall into three groups. Container platforms (Fly.io, Render, Railway, Koyeb, Northflank, Google Cloud Run) run any image you give them and bill per second or per instance. Platforms with a Java runtime (Heroku, Azure App Service, Elastic Beanstalk, Clever Cloud) take source code, a JAR or a WAR. Plain VMs (Hetzner, AWS Lightsail, Oracle Cloud) give you a Linux box and leave the JDK, the service manager and the patching to you.

Small instances are where Java needs care. A 512 MB machine is common on entry plans: Render's free web service, Heroku's Eco and Basic dynos, and DigitalOcean's $5 App Platform container all sit at that size. The JVM sizes its heap from a percentage of available memory, and the default leaves a lot unused. The Java hosting comparison lists prices, free-tier limits, regions and payment methods for each provider, and the free Java hosting page covers the free options and their catches in detail.

Logs and health checks

Two habits separate a deployment you can trust from one you have to check by hand. Write logs to standard output instead of files inside the container, because every platform collects stdout and most throw away the container's disk on restart. And expose an HTTP endpoint that answers only when the app can do real work. Spring Boot Actuator's /actuator/health is the usual choice, and platforms such as Fly.io can poll it and restart a machine that stops answering.

Set the health check grace period longer than your startup time. On an instance with a fraction of a CPU, a Spring Boot app starts noticeably slower than on your laptop, and a check that fires too early produces a restart loop that looks like a crash.

Which guide to read when

The rest of this Java deployment guide is split into three hands-on pages. Pick the one that matches where you are.

You have an app and want it online

Start with how to deploy a Java app. It goes from JDK choice to a fat JAR, a Temurin-based Dockerfile, JVM memory flags for small instances, a health check, a deployment on Fly.io, logs and a custom domain. It is the most direct way to deploy Java web apps built with Spring Boot or any framework that produces a runnable JAR.

You are learning servlets or keeping a WAR alive

Read servlets and JSP to Jakarta EE. It works as a short Java servlet tutorial with a minimal annotated servlet and a JSP page, then explains the javax to jakarta rename and the tools that migrate old code. Anyone who has to move a Tomcat 9 app forward needs it soon: Tomcat 9.0.x support ends on 31 March 2027.

You need to pick a servlet container

The Tomcat vs Jetty comparison puts current versions, spec levels, licenses and embedded use side by side, and adds WildFly, Payara, Open Liberty and GlassFish for the full Jakarta EE case. It also covers a recent change that catches people out: Spring Boot 4 dropped Undertow as an embedded server because Undertow does not yet support the Servlet 6.1 baseline.

If you would rather deploy Java web apps without touching a Dockerfile, read the hosting pages first and pick a platform with a native Java runtime. Then come back to the deploy guide for the health check and memory sections, which apply everywhere.

A shift worth remembering

Around 2000, getting a servlet onto the internet often meant a shared host running one big container for many users, an FTP upload of class files into a personal directory, and a URL under someone else's domain. The typical Java servlet tutorial of that era ended at "copy the file and reload the page." Today the same servlet runs inside a container you build yourself, on a machine billed by the second, and the hard part has moved from getting access to a JVM to keeping that JVM inside 512 MB. The developer tools overview lists the build, container and monitoring tools that cover the rest of the path.

Sources

  1. heroku.com/pricing
  2. devcenter.heroku.com/articles/java-support
  3. fly.io/docs/about/pricing
  4. koyeb.com/docs/reference/instances
  5. render.com/docs/free
  6. azure.microsoft.com/en-us/pricing/details/app-service/linux
  7. learn.microsoft.com/en-us/azure/app-service/configure-language-java-deploy-run
  8. tomcat.apache.org/whichversion.html
  9. tomcat.apache.org
  10. github.com/spring-projects/spring-boot/wiki/Spring-Boot-4.0-Migration-Guide
  11. adoptium.net/support
  12. openjdk.org/projects/jdk/27

Guides / FAQ

Good questions.
Clear answers.

Should a new Java web app be packaged as a JAR or a WAR?

For a new app, an executable JAR is the simpler default: the server is embedded, the app starts with one java -jar command, and it fits any container host. A WAR still makes sense when you deploy into an existing Tomcat, WildFly or Payara installation that several apps share, or when a platform such as Azure App Service runs Tomcat for you.

Which Java version should I deploy on?

Java 25 is the newest long-term support release, and Heroku already uses it as the default on its current stacks. Java 21 is still well supported by every major vendor. Avoid non-LTS releases such as JDK 27 in production unless you plan to upgrade every six months. Support end dates per vendor are listed on the Java versions page.

Do I need Docker to deploy a Java app?

No. Heroku and Clever Cloud build Java from source with native runtimes, Azure App Service runs a JAR or WAR directly, and a plain VM only needs a JDK and a service manager. Docker becomes useful when you want the same image to run on your laptop, in CI and on any container host without changes.

What is the cheapest way to run a small Java app?

Free tiers exist on Render, Koyeb, Google Cloud Run, Azure (F1) and Oracle Cloud's Always Free VMs, each with limits such as spin-down after inactivity or no production use. Among paid options, Fly.io lists a 512 MB machine at $3.69 per month and Koyeb starts at $1.61 per month for 256 MB. The full comparison is on the Java hosting page.

Is learning servlets still useful for modern Java work?

Yes, because Spring MVC, Jakarta REST and most Java web frameworks still run on the Servlet API underneath. Knowing how a servlet handles a request, how a WAR is laid out and what changed with the jakarta namespace makes framework errors and container logs much easier to read.

Find your next step.