Quarkus Native And Container
GitHubOfficialFirst committed by jduboisDistributed by GitHub
- Skill
- Tool integration
- Software development
- MIT
- No issues found
AutoGineer summary
Written by AutoGineer from the skill’s own files, not by the author
This skill provides a comprehensive workflow for compiling Quarkus applications into native executables using Mandrel or GraalVM. It covers the build process, troubleshooting common native-image failures such as reflection and resource registration, testing native binaries with integration tests, and generating container images and Kubernetes or OpenShift manifests for deployment.
What it does
- Builds native executables using Maven or Gradle with Mandrel or GraalVM.
- Configures reflection and resource registration to resolve common native-image runtime errors.
- Executes black-box integration tests against native binaries.
- Generates container images using Jib or Docker/Podman.
- Produces and customizes Kubernetes and OpenShift deployment manifests.
- Manages build-time vs. run-time class initialization settings.
When to use it
- When you need to optimize Quarkus application startup time and memory footprint.
- When preparing a Quarkus application for production deployment in containerized environments.
- When encountering ClassNotFoundException or initialization errors during native compilation.
- When automating the generation of Kubernetes or OpenShift deployment configurations.
Advantages
- Reduces application startup time and memory usage significantly.
- Simplifies the transition from JVM-based development to native production builds.
- Provides clear patterns for handling reflection and dynamic class loading in native mode.
- Integrates directly with standard build tools like Maven and Gradle.
Usage examples
- “How do I build a native executable for my Quarkus project using Maven?”
- The agent provides the command ./mvnw package -Dnative to trigger the native build process using the configured Mandrel or GraalVM environment.
- “My native build fails with a ClassNotFoundException. How do I fix it?”
- The agent explains how to use @RegisterForReflection or a reflection-config.json file to explicitly register classes for native-image compilation.
- “How can I generate Kubernetes manifests for my Quarkus app?”
- The agent instructs you to add the kubernetes extension and explains how to use properties like quarkus.kubernetes.replicas to customize the generated YAML.
- “How do I test my native binary?”
- The agent shows how to use @QuarkusIntegrationTest and the ./mvnw verify -Dnative command to run integration tests against the native runner.
Install
Download the skill as a ZIP:
https://autogineer.com/agent-skills/github/quarkus-native-and-container/downloadUnzip it into the cross-client skills folder of your project:
mkdir -p .agents/skills && unzip quarkus-native-and-container.zip -d .agents/skills
Documentation by jdubois
Quarkus Native and Container
Check the project's Quarkus version first. For generic (non-Quarkus) GraalVM work, use the optional java-add-graalvm-native-image-support skill if installed (otherwise see the GraalVM docs, https://www.graalvm.org/latest/reference-manual/native-image/).
Native build
# container build: no local GraalVM needed (Docker/Podman required)
./mvnw package -Dnative -Dquarkus.native.container-build=true
# local Mandrel/GraalVM (JAVA_HOME / GRAALVM_HOME must point to it)
./mvnw package -Dnative
# Gradle, Quarkus 3.10+ (add -Dquarkus.native.container-build=true without a local Mandrel)
./gradlew build -Dquarkus.native.enabled=true -Dquarkus.package.jar.enabled=false
# Gradle, older Quarkus
./gradlew build -Dquarkus.package.type=nativequarkus.package.type was deprecated in 3.10 (the 3.10 migration guide replaces it with quarkus.native.enabled and quarkus.package.jar.*); it is still accepted in 3.40 with a warning. Version gate verified with Gradle: on 3.9.5 -Dquarkus.native.enabled=true -Dquarkus.package.jar.enabled=false is ignored ("Unrecognized configuration key" warnings) and only a JVM quarkus-app is built, while -Dquarkus.package.type=native produces the native runner; on 3.10.0, 3.27.6 and 3.40.1 the new keys produce the native runner (3.10.0 also accepts the old key with the deprecation warning). The Maven native profile in the generated pom.xml already sets quarkus.native.enabled=true, quarkus.package.jar.enabled=false and skipITs=false when -Dnative is passed.
Local build verified on macOS arm64 with the Mandrel tarball for your Quarkus line from https://github.com/graalvm/mandrel/releases (mandrel-java25-macos-aarch64-25.0.4.1-Final.tar.gz for 3.40.1, extracted anywhere, JAVA_HOME pointing at its Contents/Home; Xcode command line tools are enough): 3.40.1 Maven package -Dnative took about 70 s and Gradle build with the two flags about 2.5 min; the runner is a Mach-O executable that starts in about 0.04 s, and ./mvnw verify -Dnative ran the *IT against it successfully. Quarkus checks the Mandrel/GraalVM version: 3.40 refuses 23.1 ("Out of date version of GraalVM or Mandrel detected ... Quarkus currently supports 25.0.0"), so use Mandrel 25 with 3.40 and mandrel-java21-macos-aarch64-23.1.12.1-Final with 3.27.6 (Maven verify -Dnative and Gradle both verified there).
Binary: target/*-runner (Maven) or build/*-runner (Gradle). A container build on macOS or Windows produces a Linux ELF that cannot run on the host: run it in a Linux container (for example docker run -v "$PWD/target:/w:ro" registry.access.redhat.com/ubi9/ubi-minimal /w/<name>-runner with the datasource passed through QUARKUS_DATASOURCE_* env vars), and note that ./mvnw verify -Dnative then fails in the *IT with Exit code is: '126'. Mandrel is Red Hat's GraalVM distribution for Quarkus; the container build pulls a Mandrel builder image matching the project (3.40.1 used quay.io/quarkus/ubi9-quarkus-mandrel-builder-image:jdk-25, Mandrel 25.0.4.1, about 2.5 minutes including the image pull); override it with quarkus.native.builder-image if needed. Native builds are slow and memory-hungry (several GB); do them in CI or on demand, not on every test run.
Common native failures
| Symptom | Fix |
|---|---|
ClassNotFoundException / NoSuchMethodException at runtime (reflection, JSON serialization of DTOs) | annotate with @RegisterForReflection (or @RegisterForReflection(targets = ...) on a holder class for third-party types), or put a reflection-config.json in src/main/resources and set quarkus.native.additional-build-args=-H:ReflectionConfigurationFiles=reflection-config.json |
| Missing resource files | quarkus.native.resources.includes=templates/** |
| Library not supporting native | look for a Quarkus extension, or choose another library |
| Class initialized at build time breaks | --initialize-at-run-time=... through quarkus.native.additional-build-args |
OutOfMemoryError during build | raise container memory or quarkus.native.native-image-xmx |
| Dynamic proxies / serialization | register via annotations or extension |
@RegisterForReflection(targets = ExternalDto.class)
public record ProductDto(String name) {}Prefer Quarkus extensions (they register reflection automatically) over raw libraries. Verified: a Panache + Quarkus REST app built natively and served JSON with a record DTO; Quarkus REST registers returned types itself, so @RegisterForReflection is mainly needed for types reached only reflectively (custom serialization, third-party types). Both rows were reproduced on 3.40.1 (local Mandrel 25): a resource calling Class.forName("org.acme.Hidden").getDeclaredConstructor().newInstance() returned HTTP 500 ClassNotFoundException: org.acme.Hidden in the native binary, and worked after adding src/main/resources/reflection-config.json ([{ "name": "org.acme.Hidden", "allDeclaredConstructors": true }]) with the documented -H:ReflectionConfigurationFiles=reflection-config.json (the relative file name resolves from src/main/resources). For the run-time initialization row, a static final java.util.Random in a class forced to build-time init (--initialize-at-build-time=org.acme.Holder) failed the build with "Detected an instance of Random/SplittableRandom class in the image heap ... mark it explicitly for run time initialization with '--initialize-at-run-time=<culprit>'"; switching to --initialize-at-run-time=org.acme.Holder fixed it, also combined with the reflection flag in one comma-separated quarkus.native.additional-build-args. Quarkus's generated native-image feature calls RuntimeClassInitialization.initializeAtBuildTime("") and then applies explicit run-time overrides, so classes default to build-time initialization. Your own static initializers (random seeds, clocks, env reads, threads) can therefore cause this failure too, not only libraries.
Test the native binary
@QuarkusIntegrationTest
class GreetingResourceIT extends GreetingResourceTest {}./mvnw verify -Dnative@QuarkusIntegrationTest black-box tests run in the verify phase (Failsafe) against the native binary; no CDI injection.
Container images
quarkus extension add container-image-jib # or container-image-docker
./mvnw package -Dquarkus.container-image.build=true
./mvnw package -Dnative -Dquarkus.native.container-build=true -Dquarkus.container-image.build=truecontainer-image-jib needs no Docker daemon to push: with DOCKER_HOST pointing at a non-existent socket, ./mvnw package -Dquarkus.container-image.build=true -Dquarkus.container-image.push=true -Dquarkus.container-image.registry=localhost:5055 -Dquarkus.container-image.insecure=true -Dquarkus.container-image.group=acme pushed acme/q340m:1.0.0-SNAPSHOT to a local registry:2 (3.40.1, JVM image). Without push=true Jib loads the image into a local Docker/Podman and fails with Cannot get an executable name when no container runtime is available when none is reachable. A tar-only output was not found or tested; the pushed image was not run.
Dockerfiles for manual builds live in src/main/docker (Dockerfile.jvm, Dockerfile.native, Dockerfile.native-micro). Set quarkus.container-image.registry/group/name/tag, and -Dquarkus.container-image.push=true to push. Use pinned base-image tags and run as non-root.
Kubernetes / OpenShift
quarkus extension add kubernetes # or: quarkus extension add openshift
./mvnw packageManifests are generated in target/kubernetes/kubernetes.yml (and .json) for the kubernetes extension, and in target/kubernetes/openshift.yml for openshift. Customize via properties; the prefix follows the target (quarkus.kubernetes.* for Kubernetes, quarkus.openshift.* for OpenShift):
quarkus.kubernetes.replicas=2
quarkus.kubernetes.ingress.expose=true
quarkus.kubernetes.env.secrets=app-secrets
quarkus.kubernetes.resources.requests.memory=128MiThe generated Deployment has no probes by default; with quarkus-smallrye-health installed it includes liveness, readiness and startup probes (/q/health/live, /q/health/ready, /q/health/started), and it sets envFrom.secretRef for env.secrets (verified on 3.40.1). Deploy with quarkus.kubernetes.deploy=true or kubectl apply -f target/kubernetes/kubernetes.yml. On OpenShift use the same properties under quarkus.openshift.*, expose the service with a Route via quarkus.openshift.route.expose=true (Kubernetes uses quarkus.kubernetes.ingress.expose=true instead), and apply with oc apply -f target/kubernetes/openshift.yml (or quarkus.openshift.deploy=true). Review generated YAML before applying; keep secrets out of it.
See also: native executables https://quarkus.io/guides/building-native-image; upgrades via quarkus update (https://quarkus.io/guides/update-quarkus); GraalVM release notes https://www.graalvm.org/release-notes/.
Files
- ATTRIBUTION.mdAdded by AutoGineer887 B
- LICENSELicence file added by AutoGineer1.0 KiB
- SKILL.md9.2 KiB
Requirements and compatibility
Written for: GitHub Copilot
Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta
“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.
Security
No issues found by our static scan· No issues found
A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.
Attribution and licence
- First committed by
jdubois
- Publisher
- GitHub (Official)
- Distributed by
- GitHub
- Source
- github/awesome-copilot · skills/quarkus-native-and-container · commit 797337f
- Licence
- MIT License (redistribution allowed)
- LICENSE (added by AutoGineer from LICENSE)
- ATTRIBUTION.md (written by AutoGineer)
- Synced
- Contributors
- jdubois
AutoGineer is not affiliated with or endorsed by jdubois or GitHub.
Download ZIP
The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download quarkus-native-and-container.zip