When comparing the traditional approach (maven.compiler.source and maven.compiler.target) to the modern approach (maven.compiler.release), you are choosing between basic bytecode generation and true cross-compilation safety.
Here is why maven.compiler.release is almost always the better choice for modern Java (like Java 17 or 21):
The Classic Pair (source + target)
- What they do:
sourcetells the compiler what Java syntax version you are writing (e.g., allow records or pattern matching).targettells the compiler what class-file version format to output (e.g., Java 8 bytecode).
- The Hidden Trap (API Pollution): If your project is set to target Java 8 (
target= 8), but you accidentally use a brand-new method introduced in Java 11 on theStringclass, it will compile successfully if your IDE/compiler classpath is running on JDK 21. Why? Because the compiler looks at the modern JDK’s standard library during compilation. However, when you run that code on a real Java 8 runtime, it will immediately crash with aNoSuchMethodError.
The Modern Standard (release)
- What it does: It sets
source,target, and swaps out the compiler’s bootstrap classpath to match the exact target version. - The Safety Net: If you set
<maven.compiler.release>11</maven.compiler.release>while running on JDK 21, the compiler actively restricts itself to only see the APIs that existed in Java 11. If you try to call a Java 17-only method, it will cause a hard compilation error right away, saving you from nasty runtime surprises in production.
Summary
- Use
maven.compiler.releasefor modern Java projects because it gives you foolproof cross-compilation safety and requires only one line of configuration. - Only use the separate
source/targetproperties if you are doing low-level compiler hacking or working with ancient build toolchains that do not support the--releaseflag.