Chapter 1. Compiling your Quarkus applications to native executables


As an application developer, you can use Red Hat build of Quarkus to create microservices written in Java that run on OpenShift and serverless environments. Applications compiled to native executables have small memory footprints and fast startup times.

This guide shows you how to compile the Quarkus Getting Started project into a native executable and how to configure and test the native executable. You will need the application created in Getting started with Quarkus.

Building a native executable with Red Hat build of Quarkus covers:

  • Building a native executable with a single command using a container runtime such as Podman or Docker
  • Creating a custom container image using the produced native executable
  • Creating a container image using the OpenShift Docker build strategy
  • Deploying the Quarkus native application to OpenShift
  • Configuring the native executable
  • Testing the native executable

Prerequisites

  • Have OpenJDK (JDK) 11 installed and the JAVA_HOME environment variable set to specify the location of the Java SDK.

    • Log in to the Red Hat Customer Portal to download Red Hat build of Open JDK from the Software Downloads page.
  • An OCI (Open Container Initiative) compatible container runtime, such as Podman or Docker.
  • A completed Quarkus Getting Started project.

1.1. Producing a native executable

A native binary is an executable that can be run on a specific OS or CPU architecture, for which it was produced. An example of such an executable could be:

  • an ELF binary for Linux
  • a Universal binary for Mac
  • an EXE binary for Windows

One advantage of building a native executable is to package the application and dependencies, including the JVM, in a single file. The native executable for your application then contains:

  • the application code
  • required libraries
  • Java APIs
  • a reduced version of the Java virtual machine (JVM) for improved application startup times and minimal disk and memory footprint

Globally, a user can select from two building options to produce a native executable from your Quarkus application:

  • in-container build
  • local-host build

    However, Red Hat build of Quarkus only supports in-container native compilation. For more details about local compilation, check the Building a native executable guide of the Upstream documentation.

Expand
Building optionRequiresUsesResults inBenefits

In-container build - Supported

A container runtime such as Podman or Docker

A builder image, which you can use together with RHEL8-UBI minimal, the Red Hat Universal Base Image: registry.access.redhat.com/ubi8/ubi-minimal:8.5

Linux 64-bits executable

GraalVM does not need to be set up locally, which makes CI pipelines run more efficiently.

Local-host build - Only Upstream

A local installation of GraalVM or Mandrel

Its local installation as a default for the quarkus.native.builder-image property

An executable, which has the same OS and CPU architecture as the machine on which the build is executed.

An alternative for developers that are not allowed or don’t want to use tools such as Docker or Podman. Overall faster than containers.

Prerequisites

  • Podman or Docker is installed.
  • The used container runtime must have access to the minimal amount of 8GB of memory.

Procedure

  1. Open the Getting Started project pom.xml file and verify that it includes the native profile:

    <profiles>
        <profile>
            <id>native</id>
            <properties>
                <quarkus.package.type>native</quarkus.package.type>
            </properties>
        </profile>
    </profiles>
    Copy to Clipboard Toggle word wrap
    Note

    Using the native profile allows you to create the native executable and run the native image tests.

  2. Build a native executable using one of the following methods:

    1. Docker:

      ./mvnw package -Pnative -Dquarkus.native.container-build=true
      Copy to Clipboard Toggle word wrap
    2. Podman:

      ./mvnw package -Pnative -Dquarkus.native.container-build=true -Dquarkus.native.container-runtime=podman
      Copy to Clipboard Toggle word wrap

      These commands create a *-runner binary in the target directory, where:

      • The *-runner file is the built native binary produced by Quarkus.
      • The target directory is a directory Maven creates when you build a maven application.

        Important

        Compiling a Quarkus application to a native executable consumes a lot of memory during analysis and optimization. You can limit the amount of memory used during native compilation by setting the quarkus.native.native-image-xmx configuration property. Setting low memory limits might increase the build time. For more details, refer to Native executable configuration properties section of the Compiling your Quarkus applications to native executables.

  3. Run the native executable:

    ./target/*-runner
    Copy to Clipboard Toggle word wrap

1.2. Creating a custom container image

You can create a container image from your Quarkus application using one of the following methods:

  • Creating a container manually
  • Creating a container using the OpenShift Docker build
Important

Compiling a Quarkus application to a native executable consumes a lot of memory during analysis and optimization. You can limit the amount of memory used during native compilation by setting the quarkus.native.native-image-xmx configuration property. Setting low memory limits might increase the build time.

1.2.1. Creating a container manually

This section shows you how to manually create a container image with your application for Linux X86_64. When you produce a native image using the Quarkus Native container it creates an executable that targets the Linux X86_64 operating system. If your host operating system is different from this, you will not be able to run the binary directly and you will need to create a container manually.

Your Quarkus Getting Started project includes a Dockerfile.native in the src/main/docker directory with the following content:

FROM registry.access.redhat.com/ubi8/ubi-minimal:8.5
WORKDIR /work/
RUN chown 1001 /work \
    && chmod "g+rwX" /work \
    && chown 1001:root /work
COPY --chown=1001:root target/*-runner /work/application

EXPOSE 8080
USER 1001

CMD ["./application", "-Dquarkus.http.host=0.0.0.0"]
Copy to Clipboard Toggle word wrap
Note

Universal Base Image (UBI)

The following list displays the suitable images for use with Dockerfiles.

  • Red Hat Universal Base Image 8 (UBI8). This base image was designed and engineered to be the base layer for all of your containerized applications, middleware and utilities.

    registry.access.redhat.com/ubi8/ubi:8.5
    Copy to Clipboard Toggle word wrap
  • Red Hat Universal Base Image 8 Minimal (UBI8-minimal). A stripped down UBI8 image that uses microdnf as a package manager.

    registry.access.redhat.com/ubi8/ubi-minimal:8.5
    Copy to Clipboard Toggle word wrap
  • All Red Hat Base images are available in the Red Hat Ecosystem Catalog.

Procedure

  1. Build a native Linux executable using one of the following methods:

    1. Build a native executable with Docker:

      ./mvnw package -Pnative -Dquarkus.native.container-build=true
      Copy to Clipboard Toggle word wrap
    2. Build a native executable with Podman:

      ./mvnw package -Pnative -Dquarkus.native.container-build=true -Dquarkus.native.container-runtime=podman
      Copy to Clipboard Toggle word wrap
  2. Build the container image using one of the following methods:

    1. Build the container image with Docker:

      docker build -f src/main/docker/Dockerfile.native -t quarkus-quickstart/getting-started .
      Copy to Clipboard Toggle word wrap
    2. Build the container image with Podman

      podman build -f src/main/docker/Dockerfile.native -t quarkus-quickstart/getting-started .
      Copy to Clipboard Toggle word wrap
  3. Run the container:

    1. Run the container with Docker:

      docker run -i --rm -p 8080:8080 quarkus-quickstart/getting-started
      Copy to Clipboard Toggle word wrap
    2. Run the container with Podman:

      podman run -i --rm -p 8080:8080 quarkus-quickstart/getting-started
      Copy to Clipboard Toggle word wrap

You can create a container image for your Quarkus application using the OpenShift Docker build strategy. This strategy creates a container using a build configuration in the cluster.

Prerequisites

  • You have access to a Red Hat OpenShift Container Platform cluster and the latest version of the OpenShift CLI (oc) is installed. For information about installing oc, see the "Installing the CLI" section of the Installing and configuring OpenShift Container Platform clusters guide.
  • A URL for the OpenShift API endpoint.

Procedure

  1. Log in to the OpenShift CLI:

    oc login -u <username_url>
    Copy to Clipboard Toggle word wrap
  2. Create a new project in OpenShift:

    oc new-project <project_name>
    Copy to Clipboard Toggle word wrap
  3. Create a build config based on the src/main/docker/Dockerfile.native file:

    cat src/main/docker/Dockerfile.native | oc new-build --name <build_name> --strategy=docker --dockerfile -
    Copy to Clipboard Toggle word wrap
  4. Build the project:

    oc start-build <build_name> --from-dir .
    Copy to Clipboard Toggle word wrap
  5. Deploy the project to OpenShift:

    oc new-app <build_name>
    Copy to Clipboard Toggle word wrap
  6. Expose the services:

    oc expose svc/<build_name>
    Copy to Clipboard Toggle word wrap

1.3. Native executable configuration properties

Configuration properties define how the native executable is generated. You can configure your Quarkus application using the application.properties file.

Configuration properties

The following table lists the configuration properties that you can set to define how the native executable is generated:

Expand

Property

Description

Type

Default

quarkus.native.additional-build-args

Additional arguments to pass to the build process.

list of strings

 

quarkus.native.enable-http-url-handler

Enables HTTP URL handler. This allows you to do URL.openConnection() for HTTP URLs.

boolean

true

quarkus.native.enable-https-url-handler

Enables HTTPS URL handler. This allows you to do URL.openConnection() for HTTPS URLs.

boolean

false

quarkus.native.enable-all-security-services

Adds all security services to the native image.

boolean

false

quarkus.native.add-all-charsets

Adds all character sets to the native image. This increases the image size.

boolean

false

quarkus.native.graalvm-home

Contains the path of the Graal distribution.

string

${GRAALVM_HOME:}

quarkus.native.java-home

Contains the path of the JDK.

File

${java.home}

quarkus.native.native-image-xmx

The maximum Java heap used to generate the native image.

string

 

quarkus.native.debug-build-process

Waits for a debugger to attach to the build process before running the native image build. This is an advanced option for those familiar with GraalVM internals.

boolean

false

quarkus.native.publish-debug-build-process-port

Publishes the debug port when building with docker if debug-build-process is true.

boolean

true

quarkus.native.cleanup-server

Restarts the native image server.

boolean

false

quarkus.native.enable-isolates

Enables isolates to improve memory management.

boolean

true

quarkus.native.enable-fallback-images

Creates a JVM-based fallback image if the native image fails.

boolean

false

quarkus.native.enable-server

Uses the native image server. This can speed up compilation but can result in lost changes due to cache invalidation issues.

boolean

false

quarkus.native.auto-service-loader-registration

Automatically registers all META-INF/services entries.

boolean

false

quarkus.native.dump-proxies

Dumps the bytecode of all proxies for inspection.

boolean

false

quarkus.native.container-build

Builds using a container runtime. Docker is used by default.

boolean

false

quarkus.native.builder-image

The docker image to build the image.

string

registry.access.redhat.com/quarkus/mandrel-21-rhel8:21.3

quarkus.native.container-runtime

The container runtime used build the image. For example, Docker.

string

 

quarkus.native.container-runtime-options

Options to pass to the container runtime.

list of strings

 

quarkus.native.enable-vm-inspection

Enables VM introspection in the image.

boolean

false

quarkus.native.full-stack-traces

Enables full stack traces in the image.

boolean

true

quarkus.native.enable-reports

Generates reports on call paths and included packages/classes/methods.

boolean

false

quarkus.native.report-exception-stack-traces

Reports exceptions with a full stack trace.

boolean

true

quarkus.native.report-errors-at-runtime

Reports errors at runtime. This may cause your application to fail at runtime if you use unsupported features.

boolean

false

quarkus.native.resources.includes

A comma-separated list of globs to match resource paths that should be added to the native image. Use slash (/) as a path separator on all platforms. Globs must not start with a slash. For example, if you have src/main/resources/ignored.png and src/main/resources/foo/selected.png in your source tree and one of your dependency JARs contains a bar/some.txt file, with quarkus.native.resources.includes set to foo/,bar//*.txt, the files src/main/resources/foo/selected.png and bar/some.txt will be included in the native image, while src/main/resources/ignored.png will not be included. See Supported glob features for more information.

list of strings

 

quarkus.native.debug.enabled

Enables debug and generates debug symbols in a separate .debug file. When used with quarkus.native.container-build, Red Hat build of Quarkus only supports Red Hat Enterprise Linux or other Linux distributions as they contain the binutils package that installs the objcopy utility that splits the debug info from the native image.

boolean

false

1.3.1. Supported glob features

The following table lists the supported glob features and descriptions:

Expand

Character

Feature description

*

Matches a possibly-empty sequence of characters that does not contain slash (/).

**

Matches a possibly-empty sequence of characters that might contain slash (/).

?

Matches one character, but not slash.

[abc]

Matches one character specified in the bracket, but not slash.

[a-z]

Matches one character from the range specified in the bracket, but not slash.

[!abc]

Matches one character not specified in the bracket; does not match slash.

[!a-z]

Matches one character outside the range specified in the bracket; does not match slash.

{one,two,three}

Matches any of the alternating tokens separated by commas; the tokens may contain wildcards, nested alternations, and ranges.

\

The escape character. There are three levels of escaping: application.properties parser, MicroProfile Config list converter, and Glob parser. All three levels use the backslash as the escape character.

Compiling a Quarkus application to a native executable consumes a lot of memory during analysis and optimization. You can limit the amount of memory used during native compilation by setting the quarkus.native.native-image-xmx configuration property. Setting low memory limits might increase the build time.

Procedure

  • Use one of the following methods to set a value for the quarkus.native.native-image-xmx property to limit the memory consumption during the native image build time:

    • Using the application.properties file:

      quarkus.native.native-image-xmx=<maximum_memory>
      Copy to Clipboard Toggle word wrap
    • Setting system properties:

      mvn -Pnative -Dquarkus.native.container-build=true -Dquarkus.native.native-image-xmx=<maximum_memory>
      Copy to Clipboard Toggle word wrap

      This command builds the native executable with Docker. To use Podman, add the -Dquarkus.native.container-runtime=podman argument.

Note

For example, to set the memory limit to 6 GB, enter quarkus.native.native-image-xmx=6g. The value must be a multiple of 1024 and greater than 2MB. Append the letter m or M to indicate megabytes, or g or G to indicate gigabytes.

1.4. Testing the native executable

Test the application in native mode to test the functionality of the native executable. Use the @NativeImageTest annotation to build the native executable and run tests against the HTTP endpoints.

Procedure

  1. Open the pom.xml file and verify that the native profile contains the following elements:

    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-failsafe-plugin</artifactId>
        <version>${surefire-plugin.version}</version>
        <executions>
            <execution>
                <goals>
                    <goal>integration-test</goal>
                    <goal>verify</goal>
                </goals>
                <configuration>
                    <systemPropertyVariables>
                        <native.image.path>${project.build.directory}/${project.build.finalName}-runner</native.image.path>
                        <java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
                        <maven.home>${maven.home}</maven.home>
                    </systemPropertyVariables>
                </configuration>
            </execution>
        </executions>
    </plugin>
    Copy to Clipboard Toggle word wrap

    The failsafe-maven-plugin runs integration test and indicates the location of the produced native executable.

  2. Open the src/test/java/org/acme/quickstart/NativeGreetingResourceIT.java file and verify that it includes the following content:

    package org.acme.quickstart;
    
    
    import io.quarkus.test.junit.NativeImageTest;
    
    @NativeImageTest 
    1
    
    public class NativeGreetingResourceIT extends GreetingResourceTest { 
    2
    
    
        // Run the same tests
    
    }
    Copy to Clipboard Toggle word wrap
    1
    Use another test runner that starts the application from the native file before the tests. The executable is retrieved using the native.image.path system property configured in the Failsafe Maven Plugin.
    2
    This example extends the GreetingResourceTest, but you can also create a new test.
  3. Run the test:

    ./mvnw verify -Pnative
    Copy to Clipboard Toggle word wrap

    The following example shows the output of this command:

    ./mvnw verify -Pnative
    ...
    [getting-started-1.0-SNAPSHOT-runner:18820]     universe:     587.26 ms
    [getting-started-1.0-SNAPSHOT-runner:18820]      (parse):   2,247.59 ms
    [getting-started-1.0-SNAPSHOT-runner:18820]     (inline):   1,985.70 ms
    [getting-started-1.0-SNAPSHOT-runner:18820]    (compile):  14,922.77 ms
    [getting-started-1.0-SNAPSHOT-runner:18820]      compile:  20,361.28 ms
    [getting-started-1.0-SNAPSHOT-runner:18820]        image:   2,228.30 ms
    [getting-started-1.0-SNAPSHOT-runner:18820]        write:     364.35 ms
    [getting-started-1.0-SNAPSHOT-runner:18820]      [total]:  52,777.76 ms
    [INFO]
    [INFO] --- maven-failsafe-plugin:2.22.1:integration-test (default) @ getting-started ---
    [INFO]
    [INFO] -------------------------------------------------------
    [INFO]  T E S T S
    [INFO] -------------------------------------------------------
    [INFO] Running org.acme.quickstart.NativeGreetingResourceIT
    Executing [/data/home/gsmet/git/quarkus-quickstarts/getting-started/target/getting-started-1.0-SNAPSHOT-runner, -Dquarkus.http.port=8081, -Dtest.url=http://localhost:8081, -Dquarkus.log.file.path=build/quarkus.log]
    2019-04-15 11:33:20,348 INFO  [io.quarkus] (main) Quarkus 999-SNAPSHOT started in 0.002s. Listening on: http://[::]:8081
    2019-04-15 11:33:20,348 INFO  [io.quarkus] (main) Installed features: [cdi, resteasy]
    [INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 1.387 s - in org.acme.quickstart.NativeGreetingResourceIT
    ...
    Copy to Clipboard Toggle word wrap
    Note

    Quarkus waits for 60 seconds for the native image to start before automatically failing the native tests. You can change this duration using the quarkus.test.native-image-wait-time system property.

    You can extend the wait time using the following command where <duration> is the wait time in seconds:

    ./mvnw verify -Pnative -Dquarkus.test.native-image-wait-time=<duration>
    Copy to Clipboard Toggle word wrap

When you run tests against your native application, you can only interact with its HTTP endpoints. Because tests do not run natively, you cannot link against your application’s code like you do when running tests on the JVM.

You can share your test class between your JVM and native executions and exclude certain tests using the @DisabledOnNativeImage annotation to run tests only on the JVM.

1.4.2. Testing an existing native executable

You can test against the existing executable build. This allows you to run multiple sets of tests in stages on the binary after it is built.

Procedure

  • Run a test against a native executable that is already built:

    ./mvnw test-compile failsafe:integration-test
    Copy to Clipboard Toggle word wrap

    This command runs the test against the existing native image using the Failsafe Maven Plugin.

  • Alternatively, you can specify the path to the native executable with the following command where <path> is the native image path:

    ./mvnw test-compile failsafe:integration-test -Dnative.image.path=<path>
    Copy to Clipboard Toggle word wrap
Back to top
Red Hat logoGithubredditYoutubeTwitter

Learn

Try, buy, & sell

Communities

About Red Hat Documentation

We help Red Hat users innovate and achieve their goals with our products and services with content they can trust. Explore our recent updates.

Making open source more inclusive

Red Hat is committed to replacing problematic language in our code, documentation, and web properties. For more details, see the Red Hat Blog.

About Red Hat

We deliver hardened solutions that make it easier for enterprises to work across platforms and environments, from the core datacenter to the network edge.

Theme

© 2025 Red Hat