TT Lab
Get started
Learn Learning paths Courses

Tomcat & nginx Operations

WAR Deployment in Practice, and Parallel Deployment

Continue in TT Lab

In one line

A deployment that just copies a WAR has a hole, a 404 during unpacking, and Tomcat already has a means to fill that hole (parallel deployment with ##버전, meaning a double hash followed by a version), but most sites don't know about it.

Why this is a problem

A stop-and-deploy is safe but the service is down meanwhile. If you try to avoid downtime by simply overwriting the WAR, that path returns 404 until unpacking finishes, and this time grows with the number of classes and can exceed 30 seconds. You can't dismiss it as short because those 30 seconds fall on nine in the morning on the first day of go-live.

On top of that, the failure is silent. If Tomcat starts unpacking in the middle of the copy and fails on a half-written WAR, it is left in the log but the deployment script's exit code is 0. The person who deployed believes it succeeded and goes home.

How a WAR is deployed

If you copy webapps/order.war, Tomcat unpacks it into webapps/order/ and serves it at the /order path. That is how autoDeploy="true" works. It is convenient, but there are traps in production.

Parallel deployment — the zero-downtime means Tomcat has always had

Tomcat has a feature that is not well known. If you add ##버전 (a double hash plus a version) to the file name, you can deploy several versions at the same time under the same context path.

webapps/order##001.war   ← 기존 버전
webapps/order##002.war   ← 새 버전

In this state, Tomcat behaves as follows.

That is, you move to the new version without cutting sessions. In a single-WAS environment where the traditional zero-downtime deployment of removing and adding servers at an L4 in front is not possible, this is quite a useful card.

Version strings are sorted by string comparison, so if you write ##1, ##2, ##10, ##10 comes before ##2. Pad with zeros like ##001 or use a timestamp such as ##2026-08-19_1430.

When you still do a stop-and-deploy

Parallel deployment is not a cure-all. You can't use it in the following cases.

So the practical judgment is this: if only screens and logic change, use parallel deployment; if schema, batches or global state are involved, use stop-and-deploy.

How WAR differs from an executable JAR

These days new development is done with Spring Boot fat jars, and existing systems are WARs. It is common for the two to coexist in the same organization, so it is good to lay out the differences.

Item WAR + external Tomcat Executable JAR (embedded Tomcat)
Unit of deployment WAR file JAR file
Tomcat version Managed by the server administrator (shared by several apps) Held by the app (may differ per app)
Port server.xml Launch argument / properties
Placing several apps Several contexts in one WAS Start several processes
Rollback Replace with the previous WAR Replace the process with the previous JAR
Zero downtime Parallel deployment or L4 Process replacement + LB
Operations standard WAS-based procedure documents Process/container-based procedure documents

Which way the operations organization's standard procedure documents are written governs the actual choice. Even if a JAR is technically more convenient, in an organization where monitoring, startup and backup procedures are standardized per WAS, one JAR means new procedures have to be written. That cost can exceed the technical advantage.

The minimum a deployment script must have

A deployment script worth using in the field does at least this much.

  1. Argument validation — that the WAR file actually exists and is not 0 bytes
  2. Backup — keep the current deployment with a timestamp
  3. Atomic placement — copy under a temporary name and then mv
  4. Wait for unpacking — poll for up to N seconds until the context responds
  5. Verification — that the health check URL returns 200 and the version string is the expected value
  6. Stop immediately on failure — if step 5 fails, don't report the deployment as successful

Step 4, "wait for unpacking", is especially important. Right after cp, if you curl, it is still 404. I have seen scripts that judge that as a failure and roll back, and I have seen far more scripts that print "deployment complete" without waiting and end. The latter report a failed deployment as a success. That is far worse.

What you see in the field

So the minimum a deployment script must have is fixed. Copy under a different name and then rename atomically with mv, wait until unpacking finishes, and produce the exit code only after confirming that the actual response is 200. If you check right after copying, it is still unpacking and fails, and it is also common to mistake that for a "deployment failure" and roll back.