Szabi
/Backend Engineer
As a Java developer, my biggest gripe has always been speed.
To be more specific, startup speed. Starting up a Java application with all Its JVM glory can take up to 10–15 seconds in a heavier application. In this day and age where the attention span of a user can be measured in mere 7–8 seconds, this can be problematic. Imagine waiting 10–12 seconds for your favorite Twitter user’s page to load.
Scaling Java applications can be tricky (and pricy!) in the cloud due to the nature of the ‘write once — run anywhere’ paradigm. But what if we could eliminate this cold boot issue? What if we could optimise the price we pay for our cloud infrastructure?
Introducing GraalVM native images and Quarkus
What is GraalVM, and what are native images?
GraalVM is a high-performance JDK distribution. It is designed to accelerate the execution of applications written in Java and other JVM languages while also providing runtimes for JavaScript, Ruby, Python, and a number of other popular languages. It heavily relies on compiler optimisation techniques, such as an aggressive and sophisticated inlining technique.
With GraalVM you can compile Java bytecode into a platform-specific, self-contained, native executable to achieve faster startup and smaller footprint for your application. It is using an AOT (ahead-of-time) compiler instead of a JIT one that we are used to.
Ahead-of-time compiled applications use only a fraction of the resources required by the JVM which means they cost less to run and improve utilisation. This means that although your application might consume significantly less memory and start up faster, you might have to wait a bit more for your compilation to complete.
Smaller memory footprint means that our cloud infrastructure can run on cheaper, smaller instances than we would normally run them in JVM mode.
Natively compiled applications also can benefit from starting up from a pre-booted memory snapshot. That means that frameworks that fully support native image compilation can leverage it to create configuration at compile time instead of taking time configuring your application at startup.
The image below shows memory usage and execution times in native mode.

https://www.graalvm.org/native-image/
There are several frameworks, such as Quarkus, Micronaut that fully support native image compilation. At the time of writing this article, the Spring team is still a little behind in fully supporting it, but support is on its way!
It’s not all fun and games with native images. We lose a lot of convenience features that the JVM provides, such as profiling and remote debugging.
Garbage collection is thankfully still an option in native mode tho!
How to install GraalVM and native image extension
You can install GraalVM on your machine in several ways.
- You can download the official releases from their GitHub page. They support several platforms (including Apple Silicon!) and two versions of Java. After that, you can follow this guide for your respective platform.
- Another option if you have a UNIX-like system, like Linux or MacOS, is to use SDKMan to manage your installed SKDs. It’s a great tool to manage multiple java installations and switch between them with ease. Think of this tool as NVM for Java. Follow this link to learn more about SDKMan and about how to install it.
The Quarkus framework
What is Quarkus?
A Kubernetes Native Java stack tailored for OpenJDK HotSpot and GraalVM, crafted from the best-of-breed Java libraries and standards. It encapsulates a load of features that makes it really cool to develop with it.
- Container First: Quarkus tailors your application for GraalVM and HotSpot. Amazingly fast boot time, incredibly low RSS memory (not just heap size!) offering near-instant scale-up and high-density memory utilization in container orchestration platforms like Kubernetes. They use a technique we call compile time boot, which is leveraged by using GraalVM’s native image module.
- Unifies imperative and reactive approaches: Combine both the familiar imperative code and the reactive style when developing applications.
- Community and Standards: Quarkus provides a cohesive, fun-to-use, full-stack framework by leveraging a growing list of over fifty best-of-breed libraries that you love and use. All are wired on a standard backbone.
- Kube-Native: The combination of Quarkus and Kubernetes provides an ideal environment for creating scalable, fast, and lightweight applications. Quarkus significantly increases developer productivity with tooling, pre-built integrations, application services, and more.
- Developer Joy: A cohesive platform for optimized developer joy with unified configuration and no-hassle native executable generation. Zero config, live reload in the blink of an eye. It also has integrated support for Testcontainers, which starts up relevant containers for you during development.
Quarkus also offers amazing performance both with GraalVM JVM and native image mode as well. The image below shows memory usage and time-to-first response graphs both in JVM and native mode.

A simple Quarkus application
Getting started with Quarkus is a similar experience to using SpringBoot. It has a similar process of creating a new application from scratch. Let’s create a simple application with a REST controller which we can compile to native later!
The first step is to visit https://code.quarkus.io . This page presents us with a similar interface to https://start.spring.io. You can select your desired build tool and java version. There is also a Kotlin extension if that what's floats your boat. For now, the default configuration is fine for us.
Select RESTEasy Reactive and RESTEasy Reactive Jackson` extensions and click Generate your application. This should create and download a zip package with our generated source code.
Unzip, navigate to the folder and issue the ./mvnw compile quarkus:dev command to start our application on development mode with live reload. Let's visit http://localhost:8080/hello and make sure it works.
You might have noticed it almost took a second for the application to start up in JVM mode under GraalVM. This is unacceptable 😤. Let’s compile it into a native imageQuarkus JVM startup time.

Quarkus JVM startup time.
Compiling to native
You have two ways of compiling into native images.
- If you have installed GraalVM and the native image extension, you can run the following command to compile a native image:
./mvnw package -Pnative - If you have not installed it on your own machine, you also have the option to use a Docker container that has GraalVM and the native image extension installed by default. You can use the following command for that:
./mvnw package -Pnative -Dquarkus.native.container-build=true
It might take some time to finish compilation, especially in the docker container, but after a while you should have a native executable named code-with-quarkus-1.0.0.-SNAPSHOT-runner in your target folder.
Now it started up in a matter of a couple a milliseconds. Nice!

Quarkus native startup time
Final thoughts
So there you have it. Now you can compile Quarkus applications into native images. Hopefully, this article was a helpful intro to native images and Quarkus!
If you find this helpful, share it, so others could learn from it as well!

