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

OptionWhat it costsEffortWhen the question comes back
Move to Oracle JDK 25 under the free licenceNothing for the licenceAn LTS upgrade, usually a small one from 21September 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 optionalLow: same Java version, a different vendor, a round of testingWhen that vendor stops updating 21
Buy the Oracle Java SE Universal Subscription$15 to $5.25 per employee per monthNone on the technical sideEvery 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.

Oracle support for each Java LTS release, 2014 to 2035: premier support, then extended support. Four releases lose extended support between September 2029 and January 2032. 2029 to 2032 2014 2018 2022 2026 2030 2034 Java 8 Java 11 Java 17 Java 21 Java 25 Java 29* Oct 2026 Premier support Extended support * planned
Oracle premier and extended support for each Java LTS release. Source: Oracle Java SE Support Roadmap, 15 September 2026.
ReleaseReleasedPremier support untilExtended support until
Java 8March 2014March 2022December 2030
Java 11September 2018September 2023January 2032
Java 17September 2021September 2026September 2029
Java 21September 2023September 2028September 2031
Java 25September 2025September 2030September 2033
Java 29 (planned)September 2027September 2032September 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.

Case study: an independent wine merchant’s fifteen-year-old online store and back-office ERP moved from Java 17 and Spring 5.3 to Spring 6.2 on Jakarta EE 10, with automated refactoring by OpenRewrite, and then to Java 25, the current LTS release. Results: critical and high-severity advisories cut from 47 to 0, a core upgrade of about four weeks, and 79 automated tests passing.CASE STUDY: ECOMMERCEWine merchant: Java 17 to Java 25A fifteen-year-old online store and back-officeERP moved to Java 25 and Spring 6.2 in testedsteps, with no rewrite and no feature freeze.47 to 0critical + high advisories4 weekscore upgrade79 testsall passingJava 17, Spring 5.3javax, Hibernate 5.5Spring 6.2Jakarta EE 10Java 25current LTSOpenRewriteRead the case study

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.

A Java modernization checklist in three phases. Decide: inventory JDK builds and versions in production; choose a JDK vendor and a support policy; set a target LTS release and a date per application. Prepare: check Spring and Jakarta EE support for the target; list libraries with no release for the new JDK; add tests on the flows the business relies on. Upgrade: one version step per deployment; try generational ZGC, compact object headers and the AOT cache; stay within a year of the newest LTS release.1. DECIDEInventory JDK buildsand where they runChoose a JDK vendorand a support policySet a target LTSand a date per system2. PREPARECheck the frameworkSpring or Jakarta EEList blocked librarieswith no new releaseAdd tests firston the business flows3. UPGRADEOne step per deployframework, then JDKTest JVM optionsZGC, headers, AOT cacheStay currentnext LTS within a year
Nine checks for a Java upgrade, grouped by the phase of the project that meets them.
  1. Inventory every JDK build and version that runs in production, including Java bundled inside vendor products.
  2. 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.
  3. Set a target LTS release and a date for each application, against the extended-support dates in the table above.
  4. Check that the framework supports the target: the Spring or Jakarta EE version usually has to change with the JDK.
  5. 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.
  6. Add tests on the flows the business relies on before anything moves, so a break shows up in the build and not in production.
  7. Move one version step per deployment: the framework, then the JDK, each tested and released on its own.
  8. Test the Java 25 runtime options service by service: generational ZGC, compact object headers and an AOT cache.
  9. 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.