JDK 27, the reference implementation of Java 27, reached general availability on September 15, 2026. The question that matters more than any individual feature: should a team already running JDK 25 LTS move to 27, or wait for JDK 29?
OpenJDK's JDK 27 project page confirms the GA date. Inside Java's JDK 27 GA announcement counts nine enhancements shipping as JEPs, four of them preview features and one an incubator feature. Three of the four non-preview JEPs are the ones that change how code runs in production: a garbage collector default, an object header layout, and a TLS default. This is a checklist for whoever owns that upgrade decision, not a tour of every JEP.
Is JDK 27 an LTS release?
No, and that single fact should settle the decision for most teams before any JEP does. Oracle's Java SE support roadmap lists Java SE 8, 11, 17, 21, and 25 as the LTS releases; 27 isn't on that list. Oracle's Premier Support for JDK 27 ends in March 2027, six months after GA. The next LTS release, JDK 29, isn't due until September 2027.
Compare that to where a team on JDK 25 already sits: Premier Support to September 2030, Extended Support to September 2033. Moving to 27 buys nothing over staying on 25, unless a specific JEP is needed today, and moving means doing this whole exercise again within six months, at 28 or 29. For most teams, staying on 25 until 29 ships is the lower-risk path. Move to 27 only when a specific feature justifies redoing the upgrade twice more before the next LTS lands.
G1 is now the default garbage collector everywhere
The JEP that makes G1 the default garbage collector in every environment, including constrained ones that previously fell back to Serial, changes behavior for any JVM that was quietly relying on the old default. Before JDK 27, a JVM running on a constrained box, a single-CPU CI runner, a small edge container, a low-memory VM, defaulted to Serial GC unless someone set -XX:+UseG1GC explicitly. That default flips in JDK 27. If the flag was never set, the app was on Serial; now it's on G1, the moment the version bumps.
The JEP itself flags the risk: "It is possible that some applications in constrained environments will still perform best with Serial. In such cases, you can still select Serial explicitly." Benchmark under real load before assuming the new default is neutral. If a workload was implicitly relying on Serial's smaller memory footprint, pin -XX:+UseSerialGC explicitly rather than finding the regression in production.
Compact object headers are on by default
The JEP that makes compact object headers the default layout shrinks every object header from 96 bits to 64 bits on 64-bit HotSpot. Compact headers aren't new to JDK 27: they shipped experimental in JDK 24 and became an opt-in product feature in JDK 25. JDK 27 is the version where they're on unless you turn them off.
The change doesn't touch application code directly. It does touch anything that reads object memory: an APM agent, a profiler, or native and JNI code that assumes the old 96-bit layout. Check that tooling is compact-object-header aware before upgrading. -XX:-UseCompactObjectHeaders is the escape hatch, a bridge while a vendor catches up, not a setting to leave in place indefinitely.
TLS 1.3 gets post-quantum key exchange by default
JEP 527 adds hybrid post-quantum key exchange to TLS 1.3: three ML-KEM hybrid schemes, with X25519MLKEM768 set as the most preferred by default. The JEP is explicit about the code impact: "no changes to existing code will be required in order to benefit from quantum-resistant TLS when it is available, as long as that code does not already select specific key exchange schemes."
That qualifier is the part worth checking. Any code or config that hardcodes jdk.tls.namedGroups is overriding the new default, not benefiting from it, and needs review. It's also worth smoke-testing TLS handshakes against external peers and load balancers after the upgrade; a peer that doesn't yet support the new hybrid groups is a compatibility problem better found in staging than production.
Seven APIs and options are gone, not deprecated
Oracle's JDK 27 release notes list what's been removed outright rather than deprecated with a warning. Seven items: the Linux -Djdk.lang.Process.launchMechanism=VFORK option, removed because, in Oracle's words, "the VFORK launch mechanism is inherently dangerous"; ThreadPoolExecutor.finalize(); the java.locale.useOldISOCodes system property, deprecated since JDK 25 and now a no-op that triggers a runtime warning; default JNDI/LDAP factory-property wiring; localized resource files for languages other than English, Japanese, German, and Simplified Chinese; the experimental JVM Compiler Interface, including -XX:+UseGraalJIT; and four launcher options, -noclassgc, -noverify, -verifyremote, and -Xverify:none.
ThreadPoolExecutor.finalize() is the one most likely to break a build without warning. Any subclass calling super.finalize() hits a source-compatibility break the moment it compiles against JDK 27, not a runtime warning. Grep the codebase and CI scripts for all seven before touching the version number.
The same release notes cover a change that isn't on the removed list but behaves like one: G1's heap-resizing defaults for -XX:MinHeapFreeRatio and -XX:MaxHeapFreeRatio move from 40 and 70 to 0 and 100, which the notes describe as effectively disabling G1's heap shrink and expand behavior tied to those ratios. Anything relying on System.gc()-triggered heap shrinkage needs to account for that.
How to check whether JDK 27 is safe to adopt
1. Confirm you actually need a JDK 27 feature today
If nothing in this article maps to a real requirement, staying on JDK 25 until JDK 29 ships is the lower-risk path. A team that moves to 27 without a specific need is signing up to repeat this checklist at 28 or 29, because Premier Support for 27 ends in March 2027.
2. Grep the codebase and CI scripts for the seven removed items
Search for the VFORK launch-mechanism flag, any ThreadPoolExecutor.finalize() overrides, JVMCI and -XX:+UseGraalJIT usage, the four removed launcher flags, and java.locale.useOldISOCodes. Anything that turns up needs a fix before the version bump, not after a failed build tells you about it.
3. Benchmark GC behavior under real load on constrained deployment targets
Any single-CPU CI runner, edge container, or low-memory VM that previously ran Serial by default is now running G1. Test it under realistic load rather than assuming the new default is neutral for that workload.
4. Confirm APM and profiling tooling is compact-object-header aware
Check with the vendor, or set -XX:-UseCompactObjectHeaders as a temporary bridge if the tooling hasn't caught up yet.
5. Smoke-test TLS 1.3 handshakes against external peers and load balancers
Confirm nothing hardcodes jdk.tls.namedGroups in a way that blocks the new post-quantum default, and confirm peers on the other end of a handshake can actually negotiate the new hybrid groups.
Two other releases are worth coordinating against this same checklist. Kotlin's own JVM 21+ bytecode change is a separate default flip on the same runtime, worth checking in the same upgrade cycle if the team also ships Kotlin. Teams running Java on Kubernetes should also read Kubernetes 1.37's kubelet-breaking flag removal before scheduling either upgrade.
FAQ
Is JDK 27 a long-term support (LTS) release?
No. Oracle's LTS releases are Java SE 8, 11, 17, 21, and 25. JDK 27 is non-LTS, with Premier Support ending in March 2027, six months after GA. The next LTS release is JDK 29, due September 2027.
What is the actual release date of JDK 27?
September 15, 2026, confirmed on both OpenJDK's JDK 27 project page and Oracle's own GA announcement on Inside Java.
Does upgrading to JDK 27 require any code changes for TLS?
No, in most cases. JEP 527 turns on hybrid post-quantum key exchange for TLS 1.3 by default, and the JEP states plainly that no code changes are needed to benefit from it, as long as the code doesn't already hardcode a specific key exchange scheme via jdk.tls.namedGroups. If it does, that configuration needs a review before it can pick up the new default.
What breaks if my code overrides ThreadPoolExecutor.finalize()?
The method has been removed from java.util.concurrent.ThreadPoolExecutor in JDK 27, not just deprecated. Any subclass that overrides it, especially one that calls super.finalize(), hits a source-compatibility break, a compile failure rather than a runtime warning, the moment it's compiled against JDK 27.
