Quarkus 4.0.0.Beta1 dropped on October 1st, and the final release is planned for the end of November. I’ve been building Quarkus apps since the 1.x days, so I figured I’d kick the tires and give a quick take.
Short version: there’s a lot to like here, but this is a big one. Plan accordingly.
Tools Used
- Quarkus CLI (latest)
- Java 21 (more on that below)
- Podman
- An IDE (IntelliJ IDEA, VSCode)
Kicking the Tires
Let’s spin up a project against the beta using our trusty Quarkus CLI. I’m intentionally using the same stack I used in my Quarkus 3 REST API post, because I want to see what actually breaks for a real app, not a hello world.
quarkus create app --wrapper --no-code \
-P io.quarkus.platform:quarkus-bom:4.0.0.Beta1 \
-x config-yaml,rest-jackson,hibernate-orm-panache,jdbc-postgresql,smallrye-health,micrometer-registry-prometheus \
com.stephennimmo:quarkus4-review:0.0.1-SNAPSHOT
cd quarkus4-review
quarkus dev
What I Like
Java 21 is the new baseline. Good. Virtual threads become a first-class citizen instead of an opt-in curiosity. If you’re still on 17, this is your push to move.
The Observation API. One @Observed annotation (or a programmatic API) gets you metrics and traces, and it works with both Micrometer and OpenTelemetry. I’ve wired up both separately more times than I care to admit, so I’ll take it.
Observability in the Dev UI. There’s now a built-in Observability section in dev mode with no wiring needed. Small thing, but it’s the kind of small thing that makes the Quarkus inner loop so nice.
HTTP/3, opt-in. It ships with automatic certificate generation in dev and test, so you can actually try it without a TLS science project.
JSON Merge Patch in Jakarta REST 4. I have hand-rolled way too many PATCH endpoints. Having this in the spec is overdue.
Everything Major, All at Once
Here’s the list of major version bumps landing in one release: Vert.x 5 and Netty 4.2, Jakarta REST 4, Hibernate ORM 8 with Jakarta Persistence 4.0, CDI 5.0, Prometheus client v1 under Micrometer, and Jackson 3. On Jackson 3, the Quarkus team’s own release notes say everything changed except the annotations.
Now look at the extensions in my project init above. rest-jackson, hibernate-orm-panache, micrometer-registry-prometheus. Every single one of them sits on something that just took a major version bump. That’s not an edge case. That’s the most common Quarkus REST stack out there.
I get it. A major version is exactly when you’re supposed to batch your breaking changes, and I’d rather rip the bandaid off once. But when something breaks during the upgrade, you’re going to have a hard time figuring out which layer did it. The team even admits the migration guide is denser than usual.
My advice: get to the latest 3.x (3.40 is the current LTS) first, run quarkus update, clean up every deprecation warning, and only then make the jump. And if you have dashboards or alerts built on your Prometheus metrics, diff the output of your metrics endpoint before and after. Don’t find out in prod.
Gripe #1: Stop Calling Everything Docker
A new major version was the perfect chance to clean up the naming, and it didn’t happen. Generate a new project and you still get a .dockerignore at the root, a src/main/docker folder full of files named Dockerfile.jvm and Dockerfile.native-micro, and build instructions in the comments that tell you to run docker build.
It’s 2026. The OCI spec has been the standard for years, Podman and Buildah read Containerfile and .containerignore natively, and IBM and Red Hat’s own tooling is Podman-first. These should be Containerfile.jvm, .containerignore, and podman build examples (or at least tool-neutral ones). Every one of my Quarkus posts has a line where I quietly translate docker build into podman build, and I’d love to stop doing that. Time to get rid of the antiquated naming.
Gripe #2: Move On from UBI
While we’re cleaning up the generated container files, the base images should move on from UBI too. Red Hat Hardened Images are distroless, minimal base images available at no cost. The runtime variants ship without a package manager or shell, and they run as a non-root user by default. That’s exactly what you want under a Quarkus app in production: less attack surface, fewer CVEs to chase, and nothing in the image your app doesn’t need. For a JVM build, use the OpenJDK runtime image. For a native executable, the minimal glibc core-runtime base is the natural replacement for the micro image.
# Containerfile.jvm
FROM registry.access.redhat.com/hi/openjdk:latest-runtime
# Containerfile.native
FROM registry.access.redhat.com/hi/core-runtime:latest
Wrapping Up
Quarkus 4 is a big step in the right direction. Java 21 as the floor, a cleaner observability story, and a modernized networking layer are all things I want. But it’s a heavy lift for a real app, and the runway is short.