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
- heroku.com/pricing
- devcenter.heroku.com/articles/java-support
- fly.io/docs/about/pricing
- koyeb.com/docs/reference/instances
- render.com/docs/free
- azure.microsoft.com/en-us/pricing/details/app-service/linux
- learn.microsoft.com/en-us/azure/app-service/configure-language-java-deploy-run
- tomcat.apache.org/whichversion.html
- tomcat.apache.org
- github.com/spring-projects/spring-boot/wiki/Spring-Boot-4.0-Migration-Guide
- adoptium.net/support
- openjdk.org/projects/jdk/27