Building Quarkus native applications with Mandrel
Learn how to build high-performance, ahead-of-time (AOT) compiled native binaries using Quarkus 3.x and Mandrel (the OpenJDK-aligned GraalVM distribution). This guide covers environment installation for Java 17/21, updating code to Jakarta EE 10 (jakarta.*), utilizing RESTEasy Reactive with Mutiny, and executing native compilations with Maven.
Mandrel is a downstream open-source distribution of GraalVM native image technology specifically designed to build native executables for Quarkus applications. Quarkus applications require one essential feature of GraalVM—the native-image tool—which compiles Java bytecode ahead-of-time (AOT) into standalone native binaries.
Mandrel bundles the GraalVM native-image capability directly on top of standard OpenJDK releases (such as OpenJDK 17 and OpenJDK 21) in Enterprise Linux distributions like RHEL and Fedora, as well as other Linux OS variants. Thus, Mandrel can best be described as a clean distribution of regular OpenJDK packaged with the GraalVM native-image engine.
Mandrel releases are built from the upstream GraalVM codebase with minimal modifications tailored for stability and container compatibility. Mandrel supports the exact same native image creation capabilities as GraalVM for Quarkus applications. One key difference is that Mandrel excludes support for Polyglot programming languages via the Truffle framework. Therefore, Mandrel remains strictly focused on Java and OpenJDK performance without extra language interpreters.
With Quarkus 3.x, Mandrel aligns with modern LTS JDK releases (JDK 17 and JDK 21), full support for Jakarta EE 10 specifications, and non-blocking reactive APIs powered by RESTEasy Reactive and SmallRye Mutiny.
Installing Mandrel
In order to install Mandrel locally, you must first install the required native compilation development tools and C libraries on your operating system:
On Fedora/CentOS/RHEL machines:
sudo dnf install glibc-devel zlib-devel gcc libffi-devel
On Ubuntu systems:
sudo apt install gcc zlib1g-dev libffi-dev
Then, download the latest release of Mandrel matching your target JDK (JDK 17 or JDK 21) from: https://github.com/graalvm/mandrel/releases

Extract the downloaded archive (for example, Mandrel built for Java 21):
$ tar -xf mandrel-java21-linux-amd64-24.0.0.0.Final.tar.gz
The extracted JDK distribution folder will contain standard OpenJDK and native-image binaries:
$ ls mandrel-java21-24.0.0.0.Final
bin conf demo include jmods languages legal lib LICENSE man README.md release SECURITY.md THIRD_PARTY_LICENSE.txt
Now configure your environment variables to point JAVA_HOME, GRAALVM_HOME, and PATH to the Mandrel distribution directory:
$ export JAVA_HOME="$( pwd )/mandrel-java21-24.0.0.0.Final"
$ export GRAALVM_HOME="${JAVA_HOME}"
$ export PATH="${JAVA_HOME}/bin:${PATH}"
Verify that your Java compiler and native-image tool are properly configured:
java -version
openjdk version "21.0.2" 2024-01-16
OpenJDK Runtime Environment Mandrel-24.0.0.0-Final (build 21.0.2+13-LTS)
OpenJDK 64-Bit Server VM Mandrel-24.0.0.0-Final (build 21.0.2+13-LTS, mixed mode, sharing)
Updating Application Code for Quarkus 3.x
When working with Quarkus 3.x, all standard Java EE dependencies have migrated to Jakarta EE 10. You must use the jakarta.* namespace instead of legacy javax.* imports. Additionally, Quarkus 3.x utilizes RESTEasy Reactive by default, integrated with Mutiny for non-blocking asynchronous endpoints.
Here is an example Jakarta EE 10 reactive endpoint compatible with native builds:
package org.acme;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
import io.smallrye.mutiny.Uni;
@Path("/hello")
public class GreetingResource {
@GET
@Produces(MediaType.TEXT_PLAIN)
public Uni<String> hello() {
return Uni.createFrom().item("Hello from Quarkus 3.x and Mandrel!");
}
}
Building a Quarkus 3.x Native Application with Mandrel
Now you can build your Quarkus application as a native executable using Maven:
$ curl -O -J https://code.quarkus.io/api/download
$ unzip code-with-quarkus.zip
$ cd code-with-quarkus/
$ ./mvnw package -Dnative
Note: Alternatively, if you do not want to install Mandrel locally, Quarkus can build native images using a containerized Mandrel image by adding -Dquarkus.native.container-build=true to your build command.
Once compiled, execute the native binary produced in the target directory:
$ ./target/code-with-quarkus-1.0.0-SNAPSHOT-runner
You will see output similar to the following, demonstrating near-instant boot time:
__ ____ __ _____ ___ __ ____ ______
--/ __ \/ / / / _ | / _ \/ //_/ / / / __/
-/ /_/ / /_/ / __ |/ , _/ ,</ /_/ /\ \
--\___\_\____/_/ |_/_/|_/_/|_|\____/___/
2024-03-15 10:15:20,102 INFO [io.quarkus] (main) code-with-quarkus 1.0.0-SNAPSHOT native (powered by Quarkus 3.8.2) started in 0.018s. Listening on: http://0.0.0.0:8080
2024-03-15 10:15:20,102 INFO [io.quarkus] (main) Profile prod activated.
2024-03-15 10:15:20,102 INFO [io.quarkus] (main) Installed features: [cdi, resteasy-reactive]
Verify your reactive REST endpoint using curl:
$ curl http://localhost:8080/hello
Hello from Quarkus 3.x and Mandrel!
Congratulations! You have successfully built and executed a high-performance, Jakarta EE 10 compliant native Java application using Quarkus 3.x and Mandrel.
Frequently Asked Questions (FAQs)
What is the primary difference between Oracle GraalVM and Mandrel?
Mandrel is a specialized downstream build of GraalVM native-image built directly on top of upstream OpenJDK. It omits Polyglot components (like Truffle framework support for Python, Ruby, or JavaScript) to provide a lightweight, enterprise-supported distribution specifically tuned for building native Quarkus Java binaries.
Do I need Mandrel installed on my machine to build native images?
No. If you have Docker or Podman installed, Quarkus can run Mandrel inside a builder container. Simply run ./mvnw package -Dnative -Dquarkus.native.container-build=true and Quarkus will handle the containerized Mandrel compilation automatically.
How does Quarkus 3.x handle Jakarta EE 10 and RESTEasy Reactive in native compilation?
Quarkus 3.x fully supports Jakarta EE 10 specifications (using the jakarta.* namespace) and defaults to non-blocking RESTEasy Reactive with Mutiny. During the native build process, Quarkus automatically handles reflection registration, build-time metadata initialization, and reactive stream generation for Mandrel without requiring manual reflection XML files.
Recommended Articles
A Comprehensive Comparison of WildFly Application Server and Quarkus Framework in Enterprise Java
Explore the features and use cases of WildFly and Quarkus for robust Java applications. #WildFly #Quarkus #EnterpriseJava
Mastering QuarkusIO: Building Supersonic Java Applications with Cloud-Native Features
Learn how to build supersonic Java applications using QuarkusIO, a cloud-native framework optimized for microservices. #Quarkus #Java #CloudNative
Create Standalone Quarkus Applications and Powerful Scripts Using JBang & Quarkus Command Mode
Learn how to develop standalone Quarkus applications with JBang and powerful scripts using Quarkus Command Mode. #Quarkus #Java #Microservices #CloudNative
Monitor Quarkus MicroProfile Metrics with Prometheus - A Comprehensive Tutorial
Learn how to monitor Quarkus MicroProfile metrics using Prometheus, an open-source monitoring solution. #Prometheus #Quarkus #MicroProfile #JavaMonitoring