In October 2026 Oracle moves JDK 21 updates to a licence that is not free in production. Many teams will handle it as a purchasing question, but it is the first of several deadlines: every Java LTS release in use today loses Oracle's extended support between 2029 and 2033, four of them within three years. The cheapest response is to decide your Java policy now, while those dates are still years apart.
Oracle JDK 21 licence change in October 2026
When Java 21 came out in September 2023, Oracle released its JDK under the No-Fee Terms and Conditions licence: free to use in production, commercial work included, until a year after the next LTS release. That year is ending.
Oracle's support roadmap, updated on 15 September 2026, says that JDK 21 updates from the October 2026 Critical Patch Update onward are released under the Java SE OTN licence, which already covers Java 8, 11 and 17.
OTN is free for personal and development use. Production use needs a paid subscription.
Nothing breaks in October. The JDK 21 builds you already have came out under the free licence and stay under it.
But Oracle's October update for 21, and every update after it, comes under OTN, so installing it on a production server needs a subscription. A team that neither pays nor moves ends up running a JDK that stopped getting security fixes in September.
JDK 17 went through the same change in October 2024, and JDK 25 will follow: Oracle's free updates for 25 end in September 2028.
Your options for JDK 21: switch builds, upgrade to 25 or subscribe
| Option | What it costs | Effort | When the question comes back |
|---|---|---|---|
| Move to Oracle JDK 25 under the free licence | Nothing for the licence | An LTS upgrade, usually a small one from 21 | September 2028, when free updates for 25 end |
| Stay on 21 with another OpenJDK build (Eclipse Temurin, Amazon Corretto, Microsoft Build of OpenJDK, Azul Zulu, Red Hat) | Free builds, paid support optional | Low: same Java version, a different vendor, a round of testing | When that vendor stops updating 21 |
| Buy the Oracle Java SE Universal Subscription | $15 to $5.25 per employee per month | None on the technical side | Every renewal |
How the Oracle Java SE subscription is priced
The subscription usually costs more than teams expect, because Oracle prices it per employee. Its price list counts everyone: full-time, part-time and temporary staff, and the contractors, outsourcers and consultants who support internal operations.
The count has nothing to do with how many people or servers use Java. At the list price for the smallest band, $15 per employee per month, a company of 400 people pays $72,000 a year, whether 400 of them use Java or four.
Switching OpenJDK builds or upgrading to Java 25
For most teams the choice is between the first two.
Another OpenJDK build is the quickest way to stay on 21 with security fixes, because all of these builds come from the same OpenJDK source: you replace the runtime, run your tests and redeploy. You still have to upgrade later.
Moving to 25 ends the licensing question until 2028 and puts you on the newer LTS (Temurin, for example, supports 25 until at least September 2031), but it is an upgrade, so it needs testing.
Java LTS end of life dates: 8, 11, 17, 21 and 25
Simon Ritter, deputy CTO at Azul, made the case in InfoWorld in June: the extended-support end dates of four LTS releases fall inside one window. Java 17 goes in September 2029, Java 8 in December 2030, Java 21 in September 2031 and Java 11 in January 2032.
His argument is that upgrading one version at a time, as each reaches the end of support, stops working when the deadlines fall this close together.
Azul sells extended support, so the article is not neutral, but the dates come from Oracle.
| Release | Released | Premier support until | Extended support until |
|---|---|---|---|
| Java 8 | March 2014 | March 2022 | December 2030 |
| Java 11 | September 2018 | September 2023 | January 2032 |
| Java 17 | September 2021 | September 2026 | September 2029 |
| Java 21 | September 2023 | September 2028 | September 2031 |
| Java 25 | September 2025 | September 2030 | September 2033 |
| Java 29 (planned) | September 2027 | September 2032 | September 2035 |
Java 17 left premier support this month and is now on extended support; Oracle has waived the extended-support fee until September 2029.
The next LTS, Java 29, is planned for September 2027, so by 2029 Java 25 will already be the older of two current LTS releases.
The real cost of a Java upgrade: engineering time
Deciding on the licence takes a meeting. Upgrading takes weeks of engineering time per application, and a close deadline does not make it faster.
Most of that time goes into three things: the framework (a Spring or Jakarta EE version that has to change with the JDK), the libraries (especially abandoned ones with no release for the new version) and the tests.
Without tests, a two-week upgrade can take two months.
Example: an online store moved from Java 17 to 25
Our most recent example is a fifteen-year-old online store and back-office ERP that we moved from Java 17 and Spring 5.3 to Java 25 and Spring 6.2 in about four weeks, without a feature freeze (see the case study). Most of that time went into the framework and the libraries; the JDK change itself was the smallest part.
On that system the framework set the order of work. Spring 6 needs Java 17 or later and moves from the javax to the jakarta packages, so the platform step came before the JDK: Jakarta EE 10, Spring 6.2, Spring Security 6.5, Hibernate 6.6 and Tomcat 10.1, with more than 800 files moved to the new namespaces by automated refactoring and every change reviewed. Spring also runs on a shorter support clock than Java; our Spring Boot 4 migration guide has its dates.
Several components had been abandoned by their authors, and each needed its own decision. A PDF library from 2009 was replaced with a maintained fork that keeps the same interface, so the invoice templates kept working. An old embedded workflow engine, built in too deeply to remove in one phase, was repackaged without the one class that carried its known vulnerability.
Before any framework moved, we added regression and browser tests around the flows the business relies on. They caught two breaks before release: one that would have stopped all PDF generation and one that would have broken spreadsheet imports.
Hibernate 6 is also stricter than Hibernate 5, so queries that used to pass silently failed at run time, including one that stalled the product search index at start-up. None of that shows up at compile time, which is why the tests come first.
Why developer capacity is the bottleneck
Now apply that to a company with forty Java applications, each needing two to six weeks of work. The limit is how many engineers who know those systems are free at the same time.
Forty applications at two to six weeks each is 80 to 240 engineer-weeks. With four engineers spared from feature work, that is 20 to 60 weeks of calendar time, before the first library with no release for the new version turns up.
Ritter says developer capacity is the bottleneck, and our experience agrees: a company that starts in 2029 has three years for four years of upgrades.
Spreading the work out keeps it affordable. A team that moves each application within a year of every new LTS release does the same upgrades in smaller pieces, and the 2029 to 2032 cluster becomes routine work. Our application modernization guide covers how to put a portfolio in order.
New features in Java 25 that offset the upgrade cost
A move from Java 17 or 21 to 25 picks up every release in between, and much of that work pays off without touching application code. The runtime changes below are JVM options or new defaults; the language and library changes pay off as the code is changed for other reasons. Each one links to its JDK Enhancement Proposal (JEP), which records what was measured and how. Our Java 21 vs 25 features comparison goes through every change between the two releases, with code.
Runtime and performance: gains without code changes
Virtual threads, final since Java 21 (JEP 444), let code in the ordinary blocking style serve many more concurrent requests without a rewrite to a reactive framework. Java 24 removed their main limitation: a virtual thread that blocks inside synchronized now releases its carrier thread instead of pinning it (JEP 491).
A team that tried virtual threads on 21 and backed off because of pinning should test them again on 25.
Generational ZGC keeps separate generations for young and old objects, so the collector can reclaim short-lived objects more often (JEP 439). Its stated goals are a lower risk of allocation stalls, less heap overhead and less garbage-collection CPU time, with pause times that stay under a millisecond. It became the default ZGC mode in JDK 23 and the only one in JDK 24, so on 25 -XX:+UseZGC means generational ZGC.
Compact object headers shrink the header of every object from between 96 and 128 bits to 64 bits on 64-bit platforms (JEP 450), and Java 25 made them a product feature (JEP 519). In the JEP's measurements, SPECjbb2015 used 22% less heap and 8% less CPU time in one setting and ran 15% fewer garbage collections in another, and a parallel JSON parser benchmark ran in 10% less time.
They are not on by default: -XX:+UseCompactObjectHeaders switches them on, so they can be tested one service at a time.
Ahead-of-time caching shortens startup and warm-up. A training run records which classes an application loads and links, and later runs start from that cache (JEP 483, Java 24). In the JEP's example, Spring PetClinic 3.2 started in 4.486 seconds on JDK 23 and in 2.604 seconds on JDK 24 with an AOT cache, 42% faster.
Java 25 reduced creating the cache to one option, -XX:AOTCacheOutput (JEP 514), and added method profiles to it, so the JIT compiler can compile hot code as soon as the application starts (JEP 515). That matters most for services that scale out under load or restart often.
Language and library changes that pay off as code changes
Pattern matching for switch and record patterns, final in Java 21 (JEP 441, JEP 440), replace long instanceof chains and much visitor boilerplate with one exhaustive switch that the compiler checks. Unnamed variables, final in 22, mark the parts of a pattern the code does not use (JEP 456).
Scoped values, final in Java 25, share immutable data with the methods a thread calls and with child threads, at lower space and time cost than thread-local variables (JEP 506). They are the replacement to reach for when a move to virtual threads turns up ThreadLocal caches.
Stream gatherers, final in Java 24, let a stream pipeline use custom intermediate operations, such as fixed-size windows, that the built-in operations do not cover (JEP 485). The Foreign Function and Memory API, final in Java 22, calls native libraries and works with off-heap memory without JNI (JEP 454).
Smaller changes in 25 remove ceremony: statements before super(...) in a constructor, so arguments can be validated first (JEP 513), and importing all the packages of a module in one declaration (JEP 511).
Profiling and security
JDK Flight Recorder gained exact timing and tracing for chosen methods, selected from the command line or over JMX without changing the code (JEP 520), and, as an experimental feature on Linux, more accurate CPU-time profiling (JEP 509). Both help when a performance problem shows up only in production.
Java 24 added the quantum-resistant ML-KEM and ML-DSA algorithms (JEP 496, JEP 497), and Java 25 a standard Key Derivation Function API (JEP 510).
Changes that add to the upgrade work
A few changes cost work instead. Java 24 permanently disabled the Security Manager: it can no longer be enabled at startup or installed while an application runs (JEP 486). Few server applications use it, but a system or library that does needs changing before the move.
Java 25 also removed the 32-bit x86 port (JEP 503), and structured concurrency is still a preview feature in 25 (JEP 505), so it does not belong in production code yet.
Where to start: a Java version inventory
We start where Ritter does: before deciding anything, find out what you have.
In most companies nobody can say, without checking, which JDK builds and versions run in production, where Java is bundled inside a vendor product, and which applications still run on a framework that is out of support.
A useful inventory fits on one page. For each application, list the JDK vendor and version, the framework and its version, the build tool, the test coverage and who can change it.
With that list, most decisions are straightforward: what can switch builds this month, what should move to 25 within six months, and what is old enough to need its own plan.
Java modernization checklist: key things to consider
The sections above come down to nine checks, in the order a Java upgrade meets them. We work through the same list at the start of an engagement.
- Inventory every JDK build and version that runs in production, including Java bundled inside vendor products.
- Choose a JDK vendor and a support policy for each application: an Oracle subscription, Oracle JDK 25 under the free licence until September 2028, or another OpenJDK build.
- Set a target LTS release and a date for each application, against the extended-support dates in the table above.
- Check that the framework supports the target: the Spring or Jakarta EE version usually has to change with the JDK.
- List the libraries with no release for the new JDK or framework, and decide for each one: upgrade it, replace it with a maintained fork, or repackage it.
- Add tests on the flows the business relies on before anything moves, so a break shows up in the build and not in production.
- Move one version step per deployment: the framework, then the JDK, each tested and released on its own.
- Test the Java 25 runtime options service by service: generational ZGC, compact object headers and an AOT cache.
- Keep each application within a year of the newest LTS release, so the next upgrade stays small.
If you want a second opinion, the first step of our Application Modernization Sprint produces one: a written inventory and upgrade order, with a ballpark estimate, within a week of a thirty-minute call.