Core deployment-time APIs and infrastructure for building Quarkus applications with native image support and development-time features
—
Quarkus packaging system handles the creation of various deployment artifacts including JAR files, native executables, container images, and specialized package formats. The packaging infrastructure supports multiple output formats optimized for different deployment scenarios from traditional JVM deployments to cloud-native container environments.
// Package configuration
import io.quarkus.deployment.pkg.PackageConfig;
import io.quarkus.deployment.pkg.NativeConfig;
import io.quarkus.deployment.pkg.JarConfig;
// Package build items
import io.quarkus.deployment.pkg.builditem.JarBuildItem;
import io.quarkus.deployment.pkg.builditem.NativeImageBuildItem;
import io.quarkus.deployment.pkg.builditem.UberJarBuildItem;
import io.quarkus.deployment.pkg.builditem.AppCDSBuildItem;
import io.quarkus.deployment.pkg.builditem.OutputTargetBuildItem;
import io.quarkus.deployment.pkg.builditem.ProcessInheritIODisabled;
// Package build steps
import io.quarkus.deployment.pkg.steps.JarResultBuildStep;
import io.quarkus.deployment.pkg.steps.NativeImageBuildStep;
import io.quarkus.deployment.pkg.steps.UberJarBuildStep;
import io.quarkus.deployment.pkg.steps.AppCDSBuildStep;
// Native image configuration
import io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem;
import io.quarkus.deployment.builditem.nativeimage.NativeImageResourceBuildItem;
import io.quarkus.deployment.builditem.nativeimage.RuntimeInitializedClassBuildItem;
import io.quarkus.deployment.builditem.nativeimage.NativeImageConfigBuildItem;
// Container and SBOM
import io.quarkus.deployment.images.ImageConfig;
import io.quarkus.deployment.sbom.SbomConfig;Central configuration for application packaging options.
class PackageConfig {
/**
* Package type to create
*/
@WithDefault("jar")
PackageType type;
/**
* Output file name (without extension)
*/
Optional<String> outputName;
/**
* Output directory for package
*/
@WithDefault("target")
String outputDirectory;
/**
* Whether to create AppCDS archive
*/
@WithDefault("true")
boolean createAppcds;
/**
* AppCDS configuration
*/
AppcdsConfig appcds;
/**
* Whether to add runner suffix to JAR name
*/
@WithDefault("true")
boolean addRunnerSuffix;
/**
* JAR compression configuration
*/
JarConfig jar;
/**
* Package types supported by Quarkus
*/
enum PackageType {
/**
* Standard runnable JAR with dependencies in lib/ folder
*/
JAR,
/**
* Legacy JAR format (deprecated)
*/
LEGACY_JAR,
/**
* Fast JAR with optimized startup (default)
*/
FAST_JAR,
/**
* GraalVM native executable
*/
NATIVE,
/**
* Native sources for offline compilation
*/
NATIVE_SOURCES,
/**
* Single JAR with all dependencies included
*/
UBER_JAR,
/**
* JAR optimized for mutable content updates
*/
MUTABLE_JAR
}
}Configuration specific to JAR packaging.
class JarConfig {
/**
* Compression level for JAR entries (0-9)
*/
@WithDefault("6")
int compressionLevel;
/**
* Whether to compress JAR entries
*/
@WithDefault("true")
boolean compress;
/**
* Manifest attributes to add
*/
Map<String, String> manifestAttributes;
/**
* Whether to include dependency list in manifest
*/
@WithDefault("true")
boolean addDependencyList;
/**
* User attributes in manifest
*/
Map<String, String> userConfiguredAttributes;
}Usage Examples:
// Configuration in application.properties
// quarkus.package.type=native
// quarkus.package.output-name=my-app
// quarkus.package.jar.compress=false
@BuildStep
void configurePackaging(PackageConfig packageConfig,
BuildProducer<PackageTypeBuildItem> packageType) {
packageType.produce(new PackageTypeBuildItem(packageConfig.type));
if (packageConfig.type == PackageType.UBER_JAR) {
// Additional uber JAR configuration
setupUberJarPackaging();
}
}Represents the built application JAR with metadata and dependencies.
class JarBuildItem extends SimpleBuildItem {
/**
* Path to the built JAR file
*/
Path getPath();
/**
* Original path before any transformations
*/
Optional<Path> getOriginalPath();
/**
* Package type of this JAR
*/
PackageType getType();
/**
* Path to the library directory (for JAR/FAST_JAR types)
*/
Optional<Path> getLibraryDir();
/**
* Main class specified in the JAR manifest
*/
Optional<String> getMainClass();
/**
* Class path entries for this JAR
*/
List<String> getClassPath();
}Represents an uber JAR containing all dependencies.
class UberJarBuildItem extends SimpleBuildItem {
/**
* Path to the uber JAR file
*/
Path getPath();
/**
* Original JAR path before uber JAR creation
*/
Path getOriginalJarPath();
/**
* Size of the uber JAR in bytes
*/
long getFileSize();
}Usage Examples:
@BuildStep
void buildJar(ApplicationArchivesBuildItem archives,
PackageConfig packageConfig,
MainClassBuildItem mainClass,
BuildProducer<JarBuildItem> jarProducer) throws IOException {
Path outputDir = Paths.get(packageConfig.outputDirectory);
String jarName = determineJarName(packageConfig, mainClass);
Path jarPath = outputDir.resolve(jarName + ".jar");
// Create JAR with manifest and dependencies
try (JarBuilder jarBuilder = new JarBuilder(jarPath)) {
// Add manifest
jarBuilder.addManifest(createManifest(mainClass.getClassName()));
// Add application classes
addApplicationClasses(jarBuilder, archives.getRootArchive());
// Handle dependencies based on package type
if (packageConfig.type == PackageType.FAST_JAR) {
Path libDir = setupLibraryDirectory(outputDir);
copyDependencies(archives.getApplicationArchives(), libDir);
jarProducer.produce(new JarBuildItem(jarPath, packageConfig.type, libDir));
} else if (packageConfig.type == PackageType.UBER_JAR) {
addDependenciesToJar(jarBuilder, archives.getApplicationArchives());
jarProducer.produce(new JarBuildItem(jarPath, packageConfig.type));
}
}
}
@BuildStep(onlyIf = UberJarRequested.class)
UberJarBuildItem createUberJar(JarBuildItem jar,
ApplicationArchivesBuildItem archives) throws IOException {
Path originalJar = jar.getPath();
Path uberJarPath = originalJar.getParent()
.resolve(originalJar.getFileName().toString().replace(".jar", "-uber.jar"));
try (JarBuilder uberBuilder = new JarBuilder(uberJarPath)) {
// Copy original JAR contents
addJarContents(uberBuilder, originalJar);
// Add all dependencies
for (ApplicationArchive archive : archives.getApplicationArchives()) {
addArchiveContents(uberBuilder, archive);
}
}
return new UberJarBuildItem(uberJarPath, originalJar, Files.size(uberJarPath));
}Configuration for GraalVM native image compilation.
class NativeConfig {
/**
* Whether native image building is enabled
*/
@WithDefault("false")
boolean enabled;
/**
* Additional build arguments for native-image
*/
List<String> additionalBuildArgs;
/**
* Container image to use for building native image
*/
@WithDefault("quay.io/quarkus/ubi-quarkus-mandrel-builder-image")
String builderImage;
/**
* Container runtime to use for building
*/
ContainerRuntimeConfig containerRuntime;
/**
* GraalVM installation directory
*/
Optional<String> graalvmHome;
/**
* Java version for native image
*/
Optional<String> javaHome;
/**
* Whether to enable debug info in native image
*/
@WithDefault("false")
boolean debug;
/**
* Whether to publish debug info separately
*/
@WithDefault("false")
boolean publishDebugBuildInfo;
/**
* Native image name
*/
Optional<String> outputName;
/**
* Auto service loader registration
*/
@WithDefault("false")
boolean autoServiceLoaderRegistration;
/**
* Dump generated files during build
*/
@WithDefault("false")
boolean dumpProxies;
/**
* Enable all character sets
*/
@WithDefault("false")
boolean enableAllCharsets;
/**
* Resource configuration files
*/
List<String> resourceConfigFiles;
}Represents the built native executable.
class NativeImageBuildItem extends SimpleBuildItem {
/**
* Path to the native executable
*/
Path getPath();
/**
* Size of the native executable in bytes
*/
long getFileSize();
/**
* GraalVM version used for compilation
*/
Optional<String> getGraalVMVersion();
/**
* Build time in milliseconds
*/
long getBuildTime();
/**
* Debug symbols file if generated
*/
Optional<Path> getDebugSymbolsPath();
}class ReflectiveClassBuildItem extends MultiBuildItem {
/**
* Register class for reflection
*/
static Builder builder(String... classNames);
static Builder builder(Class<?>... classes);
String getClassName();
boolean isConstructors();
boolean isMethods();
boolean isFields();
boolean isWeak();
static class Builder {
Builder constructors();
Builder constructors(boolean constructors);
Builder methods();
Builder methods(boolean methods);
Builder fields();
Builder fields(boolean fields);
Builder weak();
Builder weak(boolean weak);
ReflectiveClassBuildItem build();
}
}
class NativeImageResourceBuildItem extends MultiBuildItem {
/**
* Include resources in native image
*/
NativeImageResourceBuildItem(String... resources);
NativeImageResourceBuildItem(List<String> resources);
List<String> getResources();
}
class RuntimeInitializedClassBuildItem extends MultiBuildItem {
/**
* Initialize class at runtime (not build time)
*/
RuntimeInitializedClassBuildItem(String className);
RuntimeInitializedClassBuildItem(Class<?> clazz);
String getClassName();
}
class JniRuntimeAccessBuildItem extends MultiBuildItem {
/**
* Enable JNI runtime access for classes
*/
static Builder builder(String className);
static Builder builder(Class<?> clazz);
String getClassName();
boolean isConstructors();
boolean isMethods();
boolean isFields();
static class Builder {
Builder constructors();
Builder methods();
Builder fields();
JniRuntimeAccessBuildItem build();
}
}Usage Examples:
@BuildStep
void configureReflection(BuildProducer<ReflectiveClassBuildItem> reflection) {
// Register classes for reflection
reflection.produce(ReflectiveClassBuildItem.builder(
"com.example.MyClass",
"com.example.MyOtherClass"
).constructors().methods().fields().build());
// Register weak reflection (won't fail if class is missing)
reflection.produce(ReflectiveClassBuildItem.builder("optional.Class")
.weak().build());
}
@BuildStep
void configureNativeResources(BuildProducer<NativeImageResourceBuildItem> resources) {
// Include properties files
resources.produce(new NativeImageResourceBuildItem(
"application.properties",
"META-INF/services/*"
));
// Include templates and web resources
resources.produce(new NativeImageResourceBuildItem("templates/", "static/"));
}
@BuildStep
void configureRuntimeInit(BuildProducer<RuntimeInitializedClassBuildItem> runtimeInit) {
// Classes that must be initialized at runtime
runtimeInit.produce(new RuntimeInitializedClassBuildItem("java.util.Random"));
runtimeInit.produce(new RuntimeInitializedClassBuildItem("com.sun.crypto.provider.SunJCE"));
}
@BuildStep(onlyIf = NativeOrNativeSourcesBuild.class)
NativeImageBuildItem buildNative(JarBuildItem jar,
NativeConfig nativeConfig,
List<ReflectiveClassBuildItem> reflectiveClasses,
List<NativeImageResourceBuildItem> resources) throws IOException {
List<String> args = new ArrayList<>();
args.add("-jar");
args.add(jar.getPath().toString());
// Add reflection configuration
generateReflectionConfig(reflectiveClasses);
args.add("-H:ReflectionConfigurationFiles=reflection-config.json");
// Add resource configuration
generateResourceConfig(resources);
args.add("-H:ResourceConfigurationFiles=resource-config.json");
// Add user-provided arguments
args.addAll(nativeConfig.additionalBuildArgs);
// Determine output path
Path outputPath = determineNativeImagePath(jar, nativeConfig);
args.add("-o");
args.add(outputPath.toString());
// Execute native-image compiler
long startTime = System.currentTimeMillis();
executeNativeImageBuild(args);
long buildTime = System.currentTimeMillis() - startTime;
return new NativeImageBuildItem(outputPath, Files.size(outputPath), buildTime);
}class ContainerRuntimeConfig {
/**
* Container runtime to use (docker, podman)
*/
Optional<String> executable;
/**
* Additional options for container runtime
*/
List<String> options;
/**
* Working directory in container
*/
@WithDefault("/project")
String workingDirectory;
}class ImageConfig {
/**
* Base image for application container
*/
@WithDefault("registry.access.redhat.com/ubi8/openjdk-17-runtime")
String baseJvmImage;
/**
* Base image for native application container
*/
@WithDefault("registry.access.redhat.com/ubi8/ubi-minimal")
String baseNativeImage;
/**
* Additional JVM arguments for containerized app
*/
List<String> jvmArguments;
/**
* Additional arguments for native app
*/
List<String> arguments;
/**
* Working directory in container
*/
@WithDefault("/work/")
String workingDirectory;
/**
* User to run as in container
*/
@WithDefault("1001")
String user;
/**
* Exposed ports
*/
List<Integer> ports;
/**
* Environment variables
*/
Map<String, String> env;
/**
* Labels to add to container
*/
Map<String, String> labels;
}Usage Example:
@BuildStep(onlyIf = ContainerImageRequested.class)
void buildContainerImage(JarBuildItem jar,
Optional<NativeImageBuildItem> nativeImage,
ImageConfig imageConfig,
BuildProducer<ContainerImageBuildItem> containerImage) {
ContainerImageBuilder builder = new ContainerImageBuilder();
if (nativeImage.isPresent()) {
// Native container image
builder.from(imageConfig.baseNativeImage)
.copy(nativeImage.get().getPath(), "/application")
.workdir(imageConfig.workingDirectory)
.user(imageConfig.user)
.expose(imageConfig.ports)
.env(imageConfig.env)
.labels(imageConfig.labels)
.cmd("/application");
} else {
// JVM container image
builder.from(imageConfig.baseJvmImage)
.copy(jar.getPath(), "/deployments/app.jar");
if (jar.getLibraryDir().isPresent()) {
builder.copy(jar.getLibraryDir().get(), "/deployments/lib/");
}
builder.workdir(imageConfig.workingDirectory)
.user(imageConfig.user)
.expose(imageConfig.ports)
.env(imageConfig.env)
.labels(imageConfig.labels)
.cmd("java", "-jar", "/deployments/app.jar");
}
Path imagePath = builder.build();
containerImage.produce(new ContainerImageBuildItem(imagePath));
}Application Class Data Sharing for faster JVM startup.
class AppcdsConfig {
/**
* Whether AppCDS is enabled
*/
@WithDefault("true")
boolean enabled;
/**
* Additional JVM arguments for AppCDS generation
*/
List<String> builderJvmArgs;
/**
* Whether to use container for AppCDS generation
*/
@WithDefault("false")
boolean useContainer;
}
class AppCDSBuildItem extends SimpleBuildItem {
/**
* Path to generated AppCDS archive
*/
Path getAppCDSPath();
/**
* JVM arguments to use AppCDS archive
*/
List<String> getAppCDSJvmArgs();
}Usage Example:
@BuildStep(onlyIf = { JvmPackaging.class, AppCDSEnabled.class })
AppCDSBuildItem generateAppCDS(JarBuildItem jar,
AppcdsConfig appcdsConfig,
MainClassBuildItem mainClass) throws IOException {
Path appCDSPath = jar.getPath().getParent().resolve("app.jsa");
List<String> args = new ArrayList<>();
args.add("-Xshare:dump");
args.add("-XX:SharedArchiveFile=" + appCDSPath);
args.add("-cp");
args.add(buildClassPath(jar));
args.addAll(appcdsConfig.builderJvmArgs);
args.add(mainClass.getClassName());
// Generate AppCDS archive
executeJava(args);
List<String> jvmArgs = List.of(
"-Xshare:on",
"-XX:SharedArchiveFile=" + appCDSPath
);
return new AppCDSBuildItem(appCDSPath, jvmArgs);
}class SbomConfig {
/**
* Whether to generate SBOM
*/
@WithDefault("false")
boolean enabled;
/**
* SBOM format (spdx, cyclonedx)
*/
@WithDefault("spdx")
SbomFormat format;
/**
* Include test dependencies
*/
@WithDefault("false")
boolean includeTestDependencies;
enum SbomFormat {
SPDX, CYCLONEDX
}
}Usage Example:
@BuildStep(onlyIf = SbomEnabled.class)
void generateSbom(ApplicationArchivesBuildItem archives,
SbomConfig sbomConfig,
BuildProducer<GeneratedResourceBuildItem> resources) throws IOException {
SbomGenerator generator = SbomGenerator.create(sbomConfig.format);
// Add application information
generator.addComponent("application",
archives.getRootArchive().getKey().toString(),
"1.0.0");
// Add dependencies
for (ApplicationArchive archive : archives.getApplicationArchives()) {
ResolvedDependency dep = archive.getResolvedDependency();
generator.addDependency(
dep.getGroupId() + ":" + dep.getArtifactId(),
dep.getVersion(),
"library"
);
}
// Generate SBOM file
String sbomContent = generator.generate();
String filename = "sbom." + sbomConfig.format.name().toLowerCase();
resources.produce(new GeneratedResourceBuildItem(
"META-INF/" + filename,
sbomContent.getBytes(StandardCharsets.UTF_8)
));
}Install with Tessl CLI
npx tessl i tessl/maven-io--quarkus--quarkus-core-deployment