VOOZH about

URL: https://www.javacodegeeks.com/2025/08/graalvm-native-image-for-spring-boot-quarkus-step-by-step-production-example.html

⇱ GraalVM Native Image for Spring Boot / Quarkus: Step-by-step production example - Java Code Geeks


If you’ve heard that Java can start in milliseconds and sip memory like an espresso shot—yep, that’s GraalVM Native Image. It compiles your app ahead-of-time into a tiny, self-contained binary that’s perfect for microservices, serverless, and CLI tools. Below are pragmatic, production-ready walkthroughs for both Spring Boot and Quarkus, sprinkled with gotchas, DX tips, and ops checklists.

What you’ll need (and a few realities)

  • A recent JDK (Java 21+ is ideal), Docker/Podman for containerized builds, and enough horsepower: native builds are heavier than JVM jars. Quarkus recommends at least 4 CPUs and 4GB RAM when building in containers.
  • You can build with framework tooling (Spring Boot AOT/native) or directly with the GraalVM Native Build Tools. Frameworks layer smart defaults on top of GraalVM to smooth over reflection, resources, and proxies.

Path A: Spring Boot → Native image (production example)

We’ll package a simple HTTP service with Actuator, ready for containers and K8s.

1) Generate the project

Start from Spring Initializr with Spring Web, Actuator, and (optionally) Spring Data JPA if you’re hitting a database. Spring Boot includes native support with AOT processing and build plugins.

2) Add a tiny endpoint

@RestController
class HelloController {
 @GetMapping("/hello")
 String hello() { return "Hi from native 👋"; }
}

3) Build a native container image (recommended for prod)

Boot’s plugin integrates with Buildpacks so you don’t have to handcraft a Dockerfile:

./mvnw -Pnative spring-boot:build-image
# or Gradle:
./gradlew bootBuildImage --imageName=ghcr.io/acme/hello-native -Pnative

3) Build a native container image (recommended for prod)

Boot’s plugin integrates with Buildpacks so you don’t have to handcraft a Dockerfile:

./mvnw -Pnative spring-boot:build-image
# or Gradle:
./gradlew bootBuildImage --imageName=ghcr.io/acme/hello-native -Pnative

This produces a Linux container that already contains a GraalVM-compiled binary. It’s the simplest way to get a production image that works consistently across environments.

4) Or: build a local native binary

./mvnw -Pnative -DskipTests native:compile
# binary ends up in target/ (e.g., target/your-app)

Use this when you want to craft your own Dockerfile or run bare-metal.

5) Minimal Dockerfile (if you built the binary yourself)

FROM scratch
COPY target/your-app /app
EXPOSE 8080
ENTRYPOINT ["/app"]
docker run --rm -p 8080:8080 ghcr.io/acme/hello-native
curl :8080/hello

7) Health, metrics, readiness

Because you added Actuator, expose only the endpoints you need and wire liveness/readiness for K8s. The native binary doesn’t change your Actuator semantics—just your startup time.

Debug tip: If you hit reflection/resource errors during native build, add Spring Native hints or supply metadata—see the Reachability Metadata primer and Spring’s native docs.

Path B: Quarkus → Native image (production example)

Quarkus leans hard into GraalVM: fast dev mode, thoughtful defaults, and great native ergonomics.

1) Create & code

Use the Quarkus CLI or Maven to scaffold with REST:

quarkus create app com.acme:native-demo --extension='rest,container-image-docker'
cd native-demo

Add a resource:

@Path("/hello")
public class HelloResource {
 @GET
 @Produces(MediaType.TEXT_PLAIN)
 public String hello() { return "Hello from Quarkus native"; }
}

2) Build a native executable (local)

./mvnw package -DskipTests -Dnative
# runner at target/*-runner

3) Build in a container (consistent & portable)

./mvnw package -DskipTests -Dnative -Dquarkus.native.container-build=true

To pin the builder, add in application.properties:

quarkus.native.container-build=true
quarkus.native.builder-image=quay.io/quarkus/ubi9-quarkus-mandrel-builder-image:jdk-21
quarkus.container-image.build=true
quarkus.container-image.group=ghcr.io/acme

This uses the Mandrel/GraalVM builder inside UBI and produces a container image you can push to your registry. Quarkus recommends provisioning ≥4 CPUs / 4GB RAM to keep native builds reliable. Quarkus

4) Run the image

docker run --rm -p 8080:8080 ghcr.io/acme/native-demo:1.0.0
curl :8080/hello

5) Production flags you’ll actually use

  • -Dquarkus.native.additional-build-args=--native-image-info to surface build details.
  • -Dquarkus.native.native-image-xmx=5g if build memory is tight (slower but steadier).
  • Quarkus’ Native Reference Guide has a goldmine of troubleshooting advice for OOMs, link-at-build-time issues, and GC/runtime trade-offs.

CI/CD: fast, hermetic pipelines

Why containers for builds? Consistency. Both frameworks can produce native images entirely inside Docker/Podman, which means no GraalVM installation on runners.

GitHub Actions sketch (Spring Boot, buildpacks):

name: native-image
on: [push]
jobs:
 build:
 runs-on: ubuntu-latest
 steps:
 - uses: actions/checkout@v4
 - uses: actions/setup-java@v4
 with:
 java-version: '21'
 distribution: 'temurin'
 - name: Build native container
 run: ./mvnw -Pnative spring-boot:build-image -DskipTests
 - name: Push
 run: docker tag docker.io/library/your-app:latest ghcr.io/acme/your-app:$(git rev-parse --short HEAD) &&
 echo "$CR_PAT" | docker login ghcr.io -u USERNAME --password-stdin &&
 docker push ghcr.io/acme/your-app:$(git rev-parse --short HEAD)

GitHub Actions sketch (Quarkus, container build):

- name: Build native in container
 run: ./mvnw package -DskipTests -Dnative -Dquarkus.native.container-build=true

Observability & ops notes

  • Images are tiny and start fast, but JVM mode may still win on some long-running throughput benchmarks due to JIT optimizations. Pick native for cold-start/scale-to-zero and tight resource envelopes; use JVM for hot, CPU-bound workloads when peak throughput wins.
  • Actuator (Boot) and SmallRye/Micrometer (Quarkus) still work—just ensure any exporters you use (e.g., Prometheus) are included at build time.
  • Memory tuning differs from the JVM. Review Quarkus’ native memory guidance and GraalVM docs before setting hard limits in containers.

Troubleshooting checklist (works for both)

  1. Reflection & resources: Supply Reachability Metadata or use framework hints. The GraalVM build tools can also auto-collect metadata with the tracing agent.
  2. Third-party libs: Prefer libraries with native support; otherwise add reflect-config.json/resource entries or code-level hints.
  3. Build OOMs/timeouts: Reduce parallelism, set a build Xmx (Quarkus: -Dquarkus.native.native-image-xmx=...), or scale your CI runner.
  4. Different base images: If you need musl/static executables for Alpine or scratch, you’ll pass extra native-image flags; validate with your distro first. (Quarkus and GraalVM docs outline libc choices and constraints.)

Copy-paste “first deploy” recipes

Spring Boot (Buildpacks):

./mvnw -Pnative spring-boot:build-image \
 -Dspring-boot.build-image.imageName=ghcr.io/acme/hello-native:$(git rev-parse --short HEAD)

docker run --rm -p 8080:8080 ghcr.io/acme/hello-native:$(git rev-parse --short HEAD)

Quarkus (Container native build):

./mvnw package -DskipTests -Dnative -Dquarkus.native.container-build=true
docker run --rm -p 8080:8080 ghcr.io/acme/native-demo:1.0.0

Useful links

Final nudge

Start with containerized native builds (they’re reproducible), bake in health checks early, and keep an eye on memory during builds. Once you see a cold-start in milliseconds for real, it’s hard to go back.

Do you want to know how to develop your skillset to become a Java Rockstar?
Subscribe to our newsletter to start Rocking right now!
To get you started we give you our best selling eBooks for FREE!
1. JPA Mini Book
2. JVM Troubleshooting Guide
3. JUnit Tutorial for Unit Testing
4. Java Annotations Tutorial
5. Java Interview Questions
6. Spring Interview Questions
7. Android UI Design
and many more ....
I agree to the Terms and Privacy Policy

Thank you!

We will contact you soon.

👁 Photo of Eleftheria Drosopoulou
Eleftheria Drosopoulou
August 21st, 2025Last Updated: August 13th, 2025
0 612 4 minutes read

Eleftheria Drosopoulou

Eleftheria is an Experienced Business Analyst with a robust background in the computer software industry. Proficient in Computer Software Training, Digital Marketing, HTML Scripting, and Microsoft Office, they bring a wealth of technical skills to the table. Additionally, she has a love for writing articles on various tech subjects, showcasing a talent for translating complex concepts into accessible content.
Subscribe

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Oldest
Newest Most Voted
Back to top button
Close
wpDiscuz