I spent the better part of last week migrating a legacy monolith to a microservices architecture. You know the drill. It’s 2 AM, the coffee is stale, and you’re staring at a stack trace that makes absolutely no sense. But here’s the weird part: once I actually got the configuration sorted, the platform just… worked. No weird classloader leaks. No fighting with the specification.

If you told me three years ago that I’d be praising Jakarta EE for its developer experience, I would have laughed in your face. But here we are in January 2026, and the ecosystem has settled into a rhythm that is surprisingly pleasant. The frantic pace of 2024—when we were all scrambling to figure out if the Core Profile was actually viable—has been replaced by something much more valuable: boring reliability.

The Core Profile Gamble Paid Off

Remember when Jakarta EE 11 dropped the Core Profile and everyone freaked out about fragmentation? The concern was that we’d end up with a split ecosystem where nothing worked together. Looking back, that was the best decision the working group could have made. By stripping down the requirements to just the essentials—CDI, REST, JSON—they gave runtimes the freedom to actually optimize for the cloud without dragging around twenty years of XML baggage.

I’m seeing this in production now. We aren’t just deploying “application servers” anymore; we’re deploying focused runtimes. The distinction matters. When I spin up a service today, I’m not paying a memory tax for SOAP libraries I’ll never use.

Here is the reality of my day-to-day coding in 2026. It’s clean. It’s almost boring. And it looks a lot like this:

Microservices architecture diagram - Spring Boot Microservices Architecture Diagram Microservices ...
Microservices architecture diagram – Spring Boot Microservices Architecture Diagram Microservices …
package com.example.inventory;

import jakarta.enterprise.context.ApplicationScoped;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
import java.util.List;

@Path("/stock")
@ApplicationScoped
public class InventoryResource {

    // Records are fully citizens now, no more POJO boilerplate
    public record StockItem(String sku, int quantity, String status) {}

    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public List<StockItem> getStock() {
        // Virtual threads handle the blocking IO under the hood
        return List.of(
            new StockItem("DEV-2026", 42, "IN_STOCK"),
            new StockItem("LGCY-2024", 0, "DISCONTINUED")
        );
    }
}

See that? No heavy configuration. Records just work. The runtime handles the concurrency model. It’s what we wanted five years ago.

The Runtime Wars Are Over (Everyone Won)

For a while, it felt like a death match between Quarkus, Open Liberty, and the rest. But the market has sort of stabilized into different niches, and the recent point releases from all the major players reflect that. They aren’t trying to kill each other anymore; they’re just trying to be the best version of themselves.

Open Liberty has doubled down on that “zero migration” promise. I upgraded a cluster last Tuesday without even reading the release notes (don’t tell my boss), and it was fine. Their support for the newer JDK features—specifically the FFM API stuff that stabilized back in JDK 24/25—is practically seamless now. You don’t even notice it’s happening, which is the highest compliment I can give infrastructure software.

Quarkus, on the other hand, is still obsessively chasing startup times, but they’ve stopped breaking APIs every other week. The developer joy is still there, but the “move fast and break things” energy has matured into “move fast and actually stay up.”

And GlassFish? It’s still kicking. I don’t use it for production workloads personally, but as a reference implementation, it’s become surprisingly usable for local testing again. It’s nice to have a baseline that doesn’t require a PhD in configuration to boot up.

The JDK Catch-Up Game

Microservices architecture diagram - Microservices architecture example [10] | Download Scientific Diagram
Microservices architecture diagram – Microservices architecture example [10] | Download Scientific Diagram

The biggest shift I’ve felt over the last year is how quickly the EE ecosystem is absorbing JDK updates. It used to be that a new Java version would come out, and we’d have to wait two years for the application servers to support it. Now? It’s weeks, sometimes days.

With JDK 26 looming on the horizon for later this year, the current tooling is already prepping for it. But more importantly, we are finally really using the stuff from JDK 24 and 25. I’m talking about Gatherers for stream processing and the finalized Virtual Threads implementation. If you are still manually managing thread pools in 2026, stop. Just stop. Let the container do it. The efficiency gains we are seeing on our cloud bills are real—I’m seeing 20-30% reductions in resource usage just by updating the runtime version and letting the JVM do its job.

Spring Cloud and the “Standard”

I have to mention Spring. You can’t talk about Java without it. The latest iterations of Spring Cloud have done something interesting: they’ve stopped fighting the standard and started wrapping it. The interoperability between a Spring Boot service and a vanilla Jakarta EE service is better than it has ever been.

Microservices architecture diagram - What Is A Data Microservice Architecture?
Microservices architecture diagram – What Is A Data Microservice Architecture?

We have a hybrid environment (because who doesn’t?), and the friction is gone. The tracing headers propagate correctly. The JSON serialization is consistent. It feels like the tooling vendors finally realized that we, the developers, don’t care about their turf wars. We just want to ship code.

So, What Now?

If you’re still sitting on an old Jakarta EE 8 or (god forbid) J2EE stack, waiting for the “right time” to upgrade, you are out of excuses. The chaos of the early 2020s is over. The specs are stable. The runtimes are fast. The JDK is powerful.

My advice? Pick a runtime that supports the Core Profile. Update your JDK to at least 24 (seriously, 21 is getting old). And delete some XML. You’ll feel better.