Difference between _JAVA_OPTIONS, JAVA_TOOL_OPTIONS and JAVA_OPTS
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
_JAVA_OPTIONS, JAVA_TOOL_OPTIONS, and JAVA_OPTS are three environment variables used to pass JVM arguments, but they work at different levels. JAVA_TOOL_OPTIONS is the only one defined by the official JVM specification (JVMTI) and is picked up by every compliant JVM. _JAVA_OPTIONS is a HotSpot-specific extension that silently overrides everything. JAVA_OPTS is not recognized by the JVM at all; it is a convention used by application server startup scripts like Tomcat's catalina.sh and JBoss's standalone.sh. Choosing the wrong one causes settings to be silently ignored or to affect processes you did not intend to change.
How Each Variable Works
JAVA_TOOL_OPTIONS
This is the officially supported variable, defined in the JVMTI (JVM Tool Interface) specification. Every compliant JVM is required to check this variable on startup and prepend its contents to the command-line arguments.
Key characteristics:
- The JVM prints a message to stderr confirming it picked up the variable. This is mandatory per the specification and cannot be suppressed.
- Options from
JAVA_TOOL_OPTIONSare prepended, so explicit command-line arguments override them. - It affects every Java process started in the environment, including tools like
javac,jps,jstack, and build tools (Maven, Gradle) that spawn child JVMs.
_JAVA_OPTIONS
This is a HotSpot-specific (Oracle/OpenJDK) extension. It is not part of any specification and does not exist in all JVM implementations.
Key characteristics:
- Options from
_JAVA_OPTIONSare appended to the command line, meaning they override explicit command-line arguments. - Like
JAVA_TOOL_OPTIONS, it prints a stderr message confirming pickup. - Because it overrides explicit arguments, it can silently change behavior that was intentionally set on the command line.
- It is HotSpot-specific. IBM J9, GraalVM native-image, and other non-HotSpot JVMs may not recognize it.
JAVA_OPTS
This variable is not recognized by the JVM. It exists purely as a convention in startup scripts.
Key characteristics:
- Only works if the startup script explicitly reads it. Tomcat's
catalina.sh, WildFly'sstandalone.sh, and some other scripts include$JAVA_OPTSin thejavacommand they construct. - Has no effect when you run
javadirectly. - Does not print any pickup message because the JVM never sees it.
Comparison Table
| Feature | JAVA_TOOL_OPTIONS | _JAVA_OPTIONS | JAVA_OPTS |
| Defined by | JVMTI specification | HotSpot implementation | Convention (scripts) |
| Recognized by JVM | Yes (all compliant JVMs) | Yes (HotSpot only) | No |
| Argument position | Prepended (overridden by CLI args) | Appended (overrides CLI args) | Depends on script |
| Prints pickup message | Yes (mandatory) | Yes | No |
Affects javac, jps, etc. | Yes | Yes | No |
Affects direct java -jar | Yes | Yes | No |
| Portable across JVMs | Yes | No (HotSpot only) | N/A |
Precedence and Override Behavior
When multiple variables are set, the effective argument order matters:
The effective command line becomes:
For -Xmx (and most JVM flags), the last value wins. So the effective max heap is 1024m from _JAVA_OPTIONS, because it is appended last. This is why _JAVA_OPTIONS is considered dangerous: it silently overrides values you explicitly set on the command line.
Practical Examples
Setting Heap Size for All Java Processes
Forcing a Specific Heap Size (Cannot Be Overridden)
Configuring Tomcat Specifically
Docker Container Configuration
In Docker containers, environment variables are the standard way to configure JVM options:
Using JAVA_TOOL_OPTIONS here is preferable because it is portable and can be overridden by the container orchestrator without modifying the Dockerfile.
Kubernetes JVM Configuration
Debugging with Remote Attach
Be careful: this opens a debug port on every Java process, including mvn and gradle commands.
Which One Should You Use
| Scenario | Recommended Variable | Reason |
| Default settings for all Java processes | JAVA_TOOL_OPTIONS | Portable, overridable, spec-compliant |
| Tomcat/WildFly/JBoss configuration | JAVA_OPTS | Read by the server's startup script |
| Force a setting that cannot be overridden | _JAVA_OPTIONS | Appended last, overrides CLI (use sparingly) |
| Docker/Kubernetes environment | JAVA_TOOL_OPTIONS | Clean, portable, works with all JVMs |
| Debugging a single application | CLI arguments | No side effects on other processes |
| CI/CD pipeline defaults | JAVA_TOOL_OPTIONS | Affects build tools and tests uniformly |
Common Pitfalls
- Using
JAVA_OPTSand expecting it to work withjava -jar:JAVA_OPTSis not read by the JVM. If you setJAVA_OPTS="-Xmx1024m"and runjava -jar myapp.jar, the heap is unchanged. UseJAVA_TOOL_OPTIONSinstead. - Setting
_JAVA_OPTIONSglobally and forgetting about it: Because it overrides CLI arguments, it can silently change the behavior of build tools, IDEs, and test runners. A global_JAVA_OPTIONS="-Xmx256m"can cause out-of-memory errors in Maven builds that need more heap. - Noise from the pickup message: Both
JAVA_TOOL_OPTIONSand_JAVA_OPTIONSprint a message to stderr on every JVM startup. In scripts that parse stderr for errors, this message can trigger false alerts. The message cannot be suppressed. - Affecting unintended processes: Setting
JAVA_TOOL_OPTIONSin a shell profile means every Java process in that shell inherits it, includingjavac,jps,keytool, Maven, Gradle, and IDE-launched processes. Scope the variable to specific commands when possible:JAVA_TOOL_OPTIONS="-Xmx1g" java -jar myapp.jar. - Confusing prepend vs. append semantics:
JAVA_TOOL_OPTIONSis prepended (CLI wins),_JAVA_OPTIONSis appended (it wins). Getting this backwards leads to settings that are silently overridden. - Non-HotSpot JVMs ignoring
_JAVA_OPTIONS: If you deploy on IBM Semeru, Azul Zing, or GraalVM native images,_JAVA_OPTIONSmay be ignored entirely. UseJAVA_TOOL_OPTIONSfor portability.
Summary
JAVA_TOOL_OPTIONSis the spec-compliant, portable choice. It is prepended to the command line, so explicit CLI arguments override it. Use this as your default._JAVA_OPTIONSis HotSpot-specific and appended to the command line, meaning it overrides explicit CLI arguments. Use it only when you need to force a setting that cannot be changed.JAVA_OPTSis not a JVM variable. It is a convention used by application server startup scripts (Tomcat, WildFly). It has no effect on directjavainvocations.- In Docker and Kubernetes, use
JAVA_TOOL_OPTIONSas the environment variable for JVM configuration. - Scope JVM environment variables as narrowly as possible to avoid unintentionally affecting build tools, IDEs, and other Java processes.

