Quarkus and the Java Developer Experience
This post covers
- What is Quarkus?
- Getting started with Quarkus
- What is native executable?
- Building native executable from Java using Quarkus
- Startup time difference for Jar and native executables
- Hot code replacement for Java (For me this is one of the biggest USP of the framework)
What is Quarkus?
Quarkus is a full-stack, Kubernetes-native Java framework made for Java virtual machines (JVMs) and native compilation, optimizing Java specifically for containers and enabling it to become an effective platform for serverless, cloud, and Kubernetes environments.
Getting started with Quarkus
You would need to have Java 8 or Java 11 installed along with Maven to get started with Quarkus.
Create a Boilerplate REST project
Let’s use the Maven plugin to create a boilerplate
Now it would ask for the groupId, artifcatId, version to be entered. It would also ask if we want a REST resource (say yes) followed by the classname and the path of the rest resource. This is how it would look like
Now we have a Quarkus boilerplate project ready to be build and run.
Build the project
To create a Jar run the following command.
The build took around 16 seconds.
We cover building native executable in the next section.
Run the project
java -jar target/quarkus-hello-world-1.0-SNAPSHOT-runner.jar
Test the project
Either use curl or open it on a browser and check
What is native executable?
In the world of Java, we compile the source code to Java byte code (Job of javac). When we run this compiled code, the Java byte code is converted to machine specific code (JRE does this). What if we could compile the Java source code to machine specific code and run the machine code directly without a JRE. This is exactly what a native executable is and GraalVM native-image can do this for us.
With native executables, we don’t need the JRE to run java code anymore . Those native executables are faster to bootstrap and need less resources to run. The only thing we need to give up is the Write Once Run Anywhere (WORA). That means the code would only run on similar systems on which it was compiled. But wait! Can’t we build for a specific machine and run the code along with that machine? Yes, we could do this with a container-image. So we still get WORA as long as the container run time can run on any machine.
Building native executable from Java using Quarkus
With Quarkus we can build the following native executables
- Native executable for our development machine (Won’t run on different OS or even with same OS)
- Container image with native executable (Runs everywhere where the container runtime is supported)
1. Build native executable for our development machine
Following are the steps to create a native executable for your development machine.
- Install GraalVM
- Set GRAALVM_HOME environment variable
- Add GRAALVM_HOME/bin directory to PATH
- Install GraalVM native-image utility (Run
gu install native-image)
- Set up
CLangauge environment (Varies for different OS and covered below)
- Finally run
maven packagewith the
nativeprofile enabled (On Windows an extra step is required and covered below)
Setting up C
On a Mac run the following command
On a Linux based system run the following command
# dnf (rpm-based)
sudo dnf install gcc glibc-devel zlib-devel libstdc++-static
# Debian-based distributions:
sudo apt-get install build-essential libz-dev zlib1g-dev
On Windows 10, get the Visual Studio 2019 C++ build tools and install the checked optional packages (I have used the community edition)
Build native executable
For building the native image, we need to run the following command
mvn package -Pnative
For Windows 10, you must be using the command prompt (does not work on PowerShell yet). You need to run the following batch file before running the native maven build (The path to this file would vary depending upon the version of Visual Studio e.g. 2019, 2017 and if it Community or not)
"C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat"
I have created a cmd file (native-build-windows.cmd) which runs both the commands for me.
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat"mvn package -Pnative
Once you run this, you would get a native executable
On Mac, it creates an executable file named
quarkus-hello-world-1.0-SNAPSHOT-runner under the target directory.
On Windows-10 an exe named
quarkus-hello-world-1.0-SNAPSHOT-runner.exe is created under the target diectory.
Run this file and do a round of testing. Note this executable will not run on different OS and may not run on different machines with same OS as well. So we need to create a container image which would run irrespective of the OS.
2. Building container image with native executable
Let’s start Docker and get going. (Allow file sharing on Docker)
Run the following command
mvn package -Pnative -Dquarkus.native.container-build=true
It would again build an executable but this time if you run it on your own machine, it would fail as the container build happens on the
To run the executable, we can create a container image and run that with the following command
# Build the image
docker build -f src/main/docker/Dockerfile.native -t quarkus/quarkus-hello-world .# Run the image
docker run -i --rm -p 8080:8080 quarkus/quarkus-hello-world
ubi8/ubi-minimal:8.1 image as the runtime for the executable.
There is an easier way to create the container image. Just add the following Quarkus extension using the below command
mvn quarkus:add-extension -Dextensions=quarkus-container-image-jib
Run the following command to build the Docker image
mvn package -Pnative -Dquarkus.native.container-build=true -Dquarkus.container-image.build=true
The build took around 8 minutes.
By default the container image group is your user-name of the PC. You can change it with setting a different value for
quarkus.container-image.group in the
Now run the docker image (Replace the
docker run -I --rm -p 8080:8080 <container-image-group>/quarkus-hello-world:1.0-SNAPSHOT
Startup time difference for Jar and native executables
Here is a quick summary of the startup time for the various kinds of builds and runtime on a Windows 10 with 20GB of RAM with intel i5 processor.
The jar version took around 1.773 seconds, the native machine executable started in 0.281 seconds and the native container image started in 0.017 seconds 😊.
Hot code replacement for Java
Hot code replacement is the idea, where we replace code which is already running. This was always there, SpringBoot Dev-tools does this when the classpath gets updated. The hot code replacement with Quarkus is cool and very similar in experience to the NodeJS based eco-system (with a watch option on source files). It detects the changes on the source files, compiles them and replaces them.
Let’s see this in action
Start the project in dev mode
Now let’s return “hi” instead of “hello” (any change would do) and save the file. You would notice the source file change would be detected and it would hot replace the code.
This certainly saves a few seconds to minutes (depending on your machine 😜). ❤️ this feature.
Quarkus looks really good. I like the way it has given the much needed boost to the Java Developer experience and make us feel more productive. The supported eco-system is also promising (See it for yourself with
mvn quarkus:list-extensions). I hope you would give it a try and discover for yourself.