Skip to content

Multiple Java versions on Windows: pin JAVA_HOME per service

Verified 2 min read

Keep JDK 17 and 21 side by side, pin JAVA_HOME in each Tomcat/service wrapper, and stop relying on a machine-wide PATH switch.

Tested onStandard / Datacenter · Build 26100.33650 · x64
E1
Build
26100.33650
Edition
Standard / Datacenter
Architecture
x64
Support
Documentation (E1)
Evidence
E1Official documentation
Verified
2026-10-29
Page type
Method

Do not switch Java globally with setx JAVA_HOME and hope every service picks it up. Pin the JDK per service:

C:\Java\jdk-17\
C:\Java\jdk-21\
C:\apps\tomcat-a\setenv.bat -> JAVA_HOME=C:\Java\jdk-17
C:\apps\tomcat-b\setenv.bat -> JAVA_HOME=C:\Java\jdk-21

PATH is for your interactive shell. A Windows service gets its environment when it starts; changing the machine PATH does not retarget a running service.

  1. Download Temurin/Microsoft OpenJDK zips for each LTS.
  2. Extract to versioned directories, not C:\Program Files\Java\latest.
  3. Do not add either bin to the machine PATH unless you need a default CLI.
  4. Verify each:
Terminal window
& C:\Java\jdk-17\bin\java.exe -version
& C:\Java\jdk-21\bin\java.exe -version

Keep the full path in scripts; it is the only unambiguous selector.

Tomcat reads JAVA_HOME (or JRE_HOME) at startup. In each instance:

Terminal window
REM C:\apps\tomcat-a\bin\setenv.bat
set "JAVA_HOME=C:\Java\jdk-17"
set "CATALINA_BASE=C:\apps\tomcat-a"
Terminal window
REM C:\apps\tomcat-b\bin\setenv.bat
set "JAVA_HOME=C:\Java\jdk-21"
set "CATALINA_BASE=C:\apps\tomcat-b"

setenv.bat is per instance and survives upgrades better than editing catalina.bat. Keep CATALINA_HOME as the shared Tomcat install if you run multiple instances from one binary; keep CATALINA_BASE per instance (config, logs, webapps).

If Tomcat runs as a service, the service wrapper must capture the right environment. With the Tomcat service manager:

Terminal window
tomcat10w.exe //ES//TomcatA

Set the Java tab / JVM path to the versioned jre/jdk, or use a wrapper that reads setenv.bat. After changing, restart the service and verify the actual process:

Terminal window
Get-CimInstance Win32_Process -Filter "Name='java.exe'" |
Select-Object ProcessId, CommandLine

The command line should show the expected JDK path.

Terminal window
Invoke-WebRequest http://localhost:8080/ -UseBasicParsing | Select-Object StatusCode
Get-Content C:\apps\tomcat-a\logs\catalina.*.log -Tail 50

A Tomcat started with the wrong JDK may still boot, then fail on a class file version, TLS provider or GC option. Check the log’s “Java Home”/JVM line.

  1. Add the new JDK beside the old.
  2. Test one instance with setenv.bat.
  3. Run the app’s test suite and check TLS/keystore compatibility.
  4. Move instances one at a time.
  5. Remove the old JDK after rollback is no longer needed.

E1. The lab did not install a JDK or Tomcat; the commands are the per-service pattern to validate on Server 2025.

Sources