0
# Packaging
1
2
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.
3
4
## Core Imports
5
6
```java
7
// Package configuration
8
import io.quarkus.deployment.pkg.PackageConfig;
9
import io.quarkus.deployment.pkg.NativeConfig;
10
import io.quarkus.deployment.pkg.JarConfig;
11
12
// Package build items
13
import io.quarkus.deployment.pkg.builditem.JarBuildItem;
14
import io.quarkus.deployment.pkg.builditem.NativeImageBuildItem;
15
import io.quarkus.deployment.pkg.builditem.UberJarBuildItem;
16
import io.quarkus.deployment.pkg.builditem.AppCDSBuildItem;
17
import io.quarkus.deployment.pkg.builditem.OutputTargetBuildItem;
18
import io.quarkus.deployment.pkg.builditem.ProcessInheritIODisabled;
19
20
// Package build steps
21
import io.quarkus.deployment.pkg.steps.JarResultBuildStep;
22
import io.quarkus.deployment.pkg.steps.NativeImageBuildStep;
23
import io.quarkus.deployment.pkg.steps.UberJarBuildStep;
24
import io.quarkus.deployment.pkg.steps.AppCDSBuildStep;
25
26
// Native image configuration
27
import io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem;
28
import io.quarkus.deployment.builditem.nativeimage.NativeImageResourceBuildItem;
29
import io.quarkus.deployment.builditem.nativeimage.RuntimeInitializedClassBuildItem;
30
import io.quarkus.deployment.builditem.nativeimage.NativeImageConfigBuildItem;
31
32
// Container and SBOM
33
import io.quarkus.deployment.images.ImageConfig;
34
import io.quarkus.deployment.sbom.SbomConfig;
35
```
36
37
## Package Configuration
38
39
### PackageConfig
40
41
Central configuration for application packaging options.
42
43
```java { .api }
44
class PackageConfig {
45
/**
46
* Package type to create
47
*/
48
@WithDefault("jar")
49
PackageType type;
50
51
/**
52
* Output file name (without extension)
53
*/
54
Optional<String> outputName;
55
56
/**
57
* Output directory for package
58
*/
59
@WithDefault("target")
60
String outputDirectory;
61
62
/**
63
* Whether to create AppCDS archive
64
*/
65
@WithDefault("true")
66
boolean createAppcds;
67
68
/**
69
* AppCDS configuration
70
*/
71
AppcdsConfig appcds;
72
73
/**
74
* Whether to add runner suffix to JAR name
75
*/
76
@WithDefault("true")
77
boolean addRunnerSuffix;
78
79
/**
80
* JAR compression configuration
81
*/
82
JarConfig jar;
83
84
/**
85
* Package types supported by Quarkus
86
*/
87
enum PackageType {
88
/**
89
* Standard runnable JAR with dependencies in lib/ folder
90
*/
91
JAR,
92
93
/**
94
* Legacy JAR format (deprecated)
95
*/
96
LEGACY_JAR,
97
98
/**
99
* Fast JAR with optimized startup (default)
100
*/
101
FAST_JAR,
102
103
/**
104
* GraalVM native executable
105
*/
106
NATIVE,
107
108
/**
109
* Native sources for offline compilation
110
*/
111
NATIVE_SOURCES,
112
113
/**
114
* Single JAR with all dependencies included
115
*/
116
UBER_JAR,
117
118
/**
119
* JAR optimized for mutable content updates
120
*/
121
MUTABLE_JAR
122
}
123
}
124
```
125
126
### JarConfig
127
128
Configuration specific to JAR packaging.
129
130
```java { .api }
131
class JarConfig {
132
/**
133
* Compression level for JAR entries (0-9)
134
*/
135
@WithDefault("6")
136
int compressionLevel;
137
138
/**
139
* Whether to compress JAR entries
140
*/
141
@WithDefault("true")
142
boolean compress;
143
144
/**
145
* Manifest attributes to add
146
*/
147
Map<String, String> manifestAttributes;
148
149
/**
150
* Whether to include dependency list in manifest
151
*/
152
@WithDefault("true")
153
boolean addDependencyList;
154
155
/**
156
* User attributes in manifest
157
*/
158
Map<String, String> userConfiguredAttributes;
159
}
160
```
161
162
**Usage Examples:**
163
164
```java
165
// Configuration in application.properties
166
// quarkus.package.type=native
167
// quarkus.package.output-name=my-app
168
// quarkus.package.jar.compress=false
169
170
@BuildStep
171
void configurePackaging(PackageConfig packageConfig,
172
BuildProducer<PackageTypeBuildItem> packageType) {
173
174
packageType.produce(new PackageTypeBuildItem(packageConfig.type));
175
176
if (packageConfig.type == PackageType.UBER_JAR) {
177
// Additional uber JAR configuration
178
setupUberJarPackaging();
179
}
180
}
181
```
182
183
## JAR Packaging
184
185
### JarBuildItem
186
187
Represents the built application JAR with metadata and dependencies.
188
189
```java { .api }
190
class JarBuildItem extends SimpleBuildItem {
191
/**
192
* Path to the built JAR file
193
*/
194
Path getPath();
195
196
/**
197
* Original path before any transformations
198
*/
199
Optional<Path> getOriginalPath();
200
201
/**
202
* Package type of this JAR
203
*/
204
PackageType getType();
205
206
/**
207
* Path to the library directory (for JAR/FAST_JAR types)
208
*/
209
Optional<Path> getLibraryDir();
210
211
/**
212
* Main class specified in the JAR manifest
213
*/
214
Optional<String> getMainClass();
215
216
/**
217
* Class path entries for this JAR
218
*/
219
List<String> getClassPath();
220
}
221
```
222
223
### UberJarBuildItem
224
225
Represents an uber JAR containing all dependencies.
226
227
```java { .api }
228
class UberJarBuildItem extends SimpleBuildItem {
229
/**
230
* Path to the uber JAR file
231
*/
232
Path getPath();
233
234
/**
235
* Original JAR path before uber JAR creation
236
*/
237
Path getOriginalJarPath();
238
239
/**
240
* Size of the uber JAR in bytes
241
*/
242
long getFileSize();
243
}
244
```
245
246
**Usage Examples:**
247
248
```java
249
@BuildStep
250
void buildJar(ApplicationArchivesBuildItem archives,
251
PackageConfig packageConfig,
252
MainClassBuildItem mainClass,
253
BuildProducer<JarBuildItem> jarProducer) throws IOException {
254
255
Path outputDir = Paths.get(packageConfig.outputDirectory);
256
String jarName = determineJarName(packageConfig, mainClass);
257
Path jarPath = outputDir.resolve(jarName + ".jar");
258
259
// Create JAR with manifest and dependencies
260
try (JarBuilder jarBuilder = new JarBuilder(jarPath)) {
261
// Add manifest
262
jarBuilder.addManifest(createManifest(mainClass.getClassName()));
263
264
// Add application classes
265
addApplicationClasses(jarBuilder, archives.getRootArchive());
266
267
// Handle dependencies based on package type
268
if (packageConfig.type == PackageType.FAST_JAR) {
269
Path libDir = setupLibraryDirectory(outputDir);
270
copyDependencies(archives.getApplicationArchives(), libDir);
271
jarProducer.produce(new JarBuildItem(jarPath, packageConfig.type, libDir));
272
} else if (packageConfig.type == PackageType.UBER_JAR) {
273
addDependenciesToJar(jarBuilder, archives.getApplicationArchives());
274
jarProducer.produce(new JarBuildItem(jarPath, packageConfig.type));
275
}
276
}
277
}
278
279
@BuildStep(onlyIf = UberJarRequested.class)
280
UberJarBuildItem createUberJar(JarBuildItem jar,
281
ApplicationArchivesBuildItem archives) throws IOException {
282
283
Path originalJar = jar.getPath();
284
Path uberJarPath = originalJar.getParent()
285
.resolve(originalJar.getFileName().toString().replace(".jar", "-uber.jar"));
286
287
try (JarBuilder uberBuilder = new JarBuilder(uberJarPath)) {
288
// Copy original JAR contents
289
addJarContents(uberBuilder, originalJar);
290
291
// Add all dependencies
292
for (ApplicationArchive archive : archives.getApplicationArchives()) {
293
addArchiveContents(uberBuilder, archive);
294
}
295
}
296
297
return new UberJarBuildItem(uberJarPath, originalJar, Files.size(uberJarPath));
298
}
299
```
300
301
## Native Image Packaging
302
303
### NativeConfig
304
305
Configuration for GraalVM native image compilation.
306
307
```java { .api }
308
class NativeConfig {
309
/**
310
* Whether native image building is enabled
311
*/
312
@WithDefault("false")
313
boolean enabled;
314
315
/**
316
* Additional build arguments for native-image
317
*/
318
List<String> additionalBuildArgs;
319
320
/**
321
* Container image to use for building native image
322
*/
323
@WithDefault("quay.io/quarkus/ubi-quarkus-mandrel-builder-image")
324
String builderImage;
325
326
/**
327
* Container runtime to use for building
328
*/
329
ContainerRuntimeConfig containerRuntime;
330
331
/**
332
* GraalVM installation directory
333
*/
334
Optional<String> graalvmHome;
335
336
/**
337
* Java version for native image
338
*/
339
Optional<String> javaHome;
340
341
/**
342
* Whether to enable debug info in native image
343
*/
344
@WithDefault("false")
345
boolean debug;
346
347
/**
348
* Whether to publish debug info separately
349
*/
350
@WithDefault("false")
351
boolean publishDebugBuildInfo;
352
353
/**
354
* Native image name
355
*/
356
Optional<String> outputName;
357
358
/**
359
* Auto service loader registration
360
*/
361
@WithDefault("false")
362
boolean autoServiceLoaderRegistration;
363
364
/**
365
* Dump generated files during build
366
*/
367
@WithDefault("false")
368
boolean dumpProxies;
369
370
/**
371
* Enable all character sets
372
*/
373
@WithDefault("false")
374
boolean enableAllCharsets;
375
376
/**
377
* Resource configuration files
378
*/
379
List<String> resourceConfigFiles;
380
}
381
```
382
383
### NativeImageBuildItem
384
385
Represents the built native executable.
386
387
```java { .api }
388
class NativeImageBuildItem extends SimpleBuildItem {
389
/**
390
* Path to the native executable
391
*/
392
Path getPath();
393
394
/**
395
* Size of the native executable in bytes
396
*/
397
long getFileSize();
398
399
/**
400
* GraalVM version used for compilation
401
*/
402
Optional<String> getGraalVMVersion();
403
404
/**
405
* Build time in milliseconds
406
*/
407
long getBuildTime();
408
409
/**
410
* Debug symbols file if generated
411
*/
412
Optional<Path> getDebugSymbolsPath();
413
}
414
```
415
416
### Native Image Configuration Build Items
417
418
```java { .api }
419
class ReflectiveClassBuildItem extends MultiBuildItem {
420
/**
421
* Register class for reflection
422
*/
423
static Builder builder(String... classNames);
424
static Builder builder(Class<?>... classes);
425
426
String getClassName();
427
boolean isConstructors();
428
boolean isMethods();
429
boolean isFields();
430
boolean isWeak();
431
432
static class Builder {
433
Builder constructors();
434
Builder constructors(boolean constructors);
435
Builder methods();
436
Builder methods(boolean methods);
437
Builder fields();
438
Builder fields(boolean fields);
439
Builder weak();
440
Builder weak(boolean weak);
441
ReflectiveClassBuildItem build();
442
}
443
}
444
445
class NativeImageResourceBuildItem extends MultiBuildItem {
446
/**
447
* Include resources in native image
448
*/
449
NativeImageResourceBuildItem(String... resources);
450
NativeImageResourceBuildItem(List<String> resources);
451
452
List<String> getResources();
453
}
454
455
class RuntimeInitializedClassBuildItem extends MultiBuildItem {
456
/**
457
* Initialize class at runtime (not build time)
458
*/
459
RuntimeInitializedClassBuildItem(String className);
460
RuntimeInitializedClassBuildItem(Class<?> clazz);
461
462
String getClassName();
463
}
464
465
class JniRuntimeAccessBuildItem extends MultiBuildItem {
466
/**
467
* Enable JNI runtime access for classes
468
*/
469
static Builder builder(String className);
470
static Builder builder(Class<?> clazz);
471
472
String getClassName();
473
boolean isConstructors();
474
boolean isMethods();
475
boolean isFields();
476
477
static class Builder {
478
Builder constructors();
479
Builder methods();
480
Builder fields();
481
JniRuntimeAccessBuildItem build();
482
}
483
}
484
```
485
486
**Usage Examples:**
487
488
```java
489
@BuildStep
490
void configureReflection(BuildProducer<ReflectiveClassBuildItem> reflection) {
491
// Register classes for reflection
492
reflection.produce(ReflectiveClassBuildItem.builder(
493
"com.example.MyClass",
494
"com.example.MyOtherClass"
495
).constructors().methods().fields().build());
496
497
// Register weak reflection (won't fail if class is missing)
498
reflection.produce(ReflectiveClassBuildItem.builder("optional.Class")
499
.weak().build());
500
}
501
502
@BuildStep
503
void configureNativeResources(BuildProducer<NativeImageResourceBuildItem> resources) {
504
// Include properties files
505
resources.produce(new NativeImageResourceBuildItem(
506
"application.properties",
507
"META-INF/services/*"
508
));
509
510
// Include templates and web resources
511
resources.produce(new NativeImageResourceBuildItem("templates/", "static/"));
512
}
513
514
@BuildStep
515
void configureRuntimeInit(BuildProducer<RuntimeInitializedClassBuildItem> runtimeInit) {
516
// Classes that must be initialized at runtime
517
runtimeInit.produce(new RuntimeInitializedClassBuildItem("java.util.Random"));
518
runtimeInit.produce(new RuntimeInitializedClassBuildItem("com.sun.crypto.provider.SunJCE"));
519
}
520
521
@BuildStep(onlyIf = NativeOrNativeSourcesBuild.class)
522
NativeImageBuildItem buildNative(JarBuildItem jar,
523
NativeConfig nativeConfig,
524
List<ReflectiveClassBuildItem> reflectiveClasses,
525
List<NativeImageResourceBuildItem> resources) throws IOException {
526
527
List<String> args = new ArrayList<>();
528
args.add("-jar");
529
args.add(jar.getPath().toString());
530
531
// Add reflection configuration
532
generateReflectionConfig(reflectiveClasses);
533
args.add("-H:ReflectionConfigurationFiles=reflection-config.json");
534
535
// Add resource configuration
536
generateResourceConfig(resources);
537
args.add("-H:ResourceConfigurationFiles=resource-config.json");
538
539
// Add user-provided arguments
540
args.addAll(nativeConfig.additionalBuildArgs);
541
542
// Determine output path
543
Path outputPath = determineNativeImagePath(jar, nativeConfig);
544
args.add("-o");
545
args.add(outputPath.toString());
546
547
// Execute native-image compiler
548
long startTime = System.currentTimeMillis();
549
executeNativeImageBuild(args);
550
long buildTime = System.currentTimeMillis() - startTime;
551
552
return new NativeImageBuildItem(outputPath, Files.size(outputPath), buildTime);
553
}
554
```
555
556
## Container Integration
557
558
### Container Runtime Configuration
559
560
```java { .api }
561
class ContainerRuntimeConfig {
562
/**
563
* Container runtime to use (docker, podman)
564
*/
565
Optional<String> executable;
566
567
/**
568
* Additional options for container runtime
569
*/
570
List<String> options;
571
572
/**
573
* Working directory in container
574
*/
575
@WithDefault("/project")
576
String workingDirectory;
577
}
578
```
579
580
### Image Configuration
581
582
```java { .api }
583
class ImageConfig {
584
/**
585
* Base image for application container
586
*/
587
@WithDefault("registry.access.redhat.com/ubi8/openjdk-17-runtime")
588
String baseJvmImage;
589
590
/**
591
* Base image for native application container
592
*/
593
@WithDefault("registry.access.redhat.com/ubi8/ubi-minimal")
594
String baseNativeImage;
595
596
/**
597
* Additional JVM arguments for containerized app
598
*/
599
List<String> jvmArguments;
600
601
/**
602
* Additional arguments for native app
603
*/
604
List<String> arguments;
605
606
/**
607
* Working directory in container
608
*/
609
@WithDefault("/work/")
610
String workingDirectory;
611
612
/**
613
* User to run as in container
614
*/
615
@WithDefault("1001")
616
String user;
617
618
/**
619
* Exposed ports
620
*/
621
List<Integer> ports;
622
623
/**
624
* Environment variables
625
*/
626
Map<String, String> env;
627
628
/**
629
* Labels to add to container
630
*/
631
Map<String, String> labels;
632
}
633
```
634
635
**Usage Example:**
636
637
```java
638
@BuildStep(onlyIf = ContainerImageRequested.class)
639
void buildContainerImage(JarBuildItem jar,
640
Optional<NativeImageBuildItem> nativeImage,
641
ImageConfig imageConfig,
642
BuildProducer<ContainerImageBuildItem> containerImage) {
643
644
ContainerImageBuilder builder = new ContainerImageBuilder();
645
646
if (nativeImage.isPresent()) {
647
// Native container image
648
builder.from(imageConfig.baseNativeImage)
649
.copy(nativeImage.get().getPath(), "/application")
650
.workdir(imageConfig.workingDirectory)
651
.user(imageConfig.user)
652
.expose(imageConfig.ports)
653
.env(imageConfig.env)
654
.labels(imageConfig.labels)
655
.cmd("/application");
656
} else {
657
// JVM container image
658
builder.from(imageConfig.baseJvmImage)
659
.copy(jar.getPath(), "/deployments/app.jar");
660
661
if (jar.getLibraryDir().isPresent()) {
662
builder.copy(jar.getLibraryDir().get(), "/deployments/lib/");
663
}
664
665
builder.workdir(imageConfig.workingDirectory)
666
.user(imageConfig.user)
667
.expose(imageConfig.ports)
668
.env(imageConfig.env)
669
.labels(imageConfig.labels)
670
.cmd("java", "-jar", "/deployments/app.jar");
671
}
672
673
Path imagePath = builder.build();
674
containerImage.produce(new ContainerImageBuildItem(imagePath));
675
}
676
```
677
678
## AppCDS Support
679
680
### AppCDS Configuration
681
682
Application Class Data Sharing for faster JVM startup.
683
684
```java { .api }
685
class AppcdsConfig {
686
/**
687
* Whether AppCDS is enabled
688
*/
689
@WithDefault("true")
690
boolean enabled;
691
692
/**
693
* Additional JVM arguments for AppCDS generation
694
*/
695
List<String> builderJvmArgs;
696
697
/**
698
* Whether to use container for AppCDS generation
699
*/
700
@WithDefault("false")
701
boolean useContainer;
702
}
703
704
class AppCDSBuildItem extends SimpleBuildItem {
705
/**
706
* Path to generated AppCDS archive
707
*/
708
Path getAppCDSPath();
709
710
/**
711
* JVM arguments to use AppCDS archive
712
*/
713
List<String> getAppCDSJvmArgs();
714
}
715
```
716
717
**Usage Example:**
718
719
```java
720
@BuildStep(onlyIf = { JvmPackaging.class, AppCDSEnabled.class })
721
AppCDSBuildItem generateAppCDS(JarBuildItem jar,
722
AppcdsConfig appcdsConfig,
723
MainClassBuildItem mainClass) throws IOException {
724
725
Path appCDSPath = jar.getPath().getParent().resolve("app.jsa");
726
727
List<String> args = new ArrayList<>();
728
args.add("-Xshare:dump");
729
args.add("-XX:SharedArchiveFile=" + appCDSPath);
730
args.add("-cp");
731
args.add(buildClassPath(jar));
732
args.addAll(appcdsConfig.builderJvmArgs);
733
args.add(mainClass.getClassName());
734
735
// Generate AppCDS archive
736
executeJava(args);
737
738
List<String> jvmArgs = List.of(
739
"-Xshare:on",
740
"-XX:SharedArchiveFile=" + appCDSPath
741
);
742
743
return new AppCDSBuildItem(appCDSPath, jvmArgs);
744
}
745
```
746
747
## Software Bill of Materials (SBOM)
748
749
### SBOM Configuration and Generation
750
751
```java { .api }
752
class SbomConfig {
753
/**
754
* Whether to generate SBOM
755
*/
756
@WithDefault("false")
757
boolean enabled;
758
759
/**
760
* SBOM format (spdx, cyclonedx)
761
*/
762
@WithDefault("spdx")
763
SbomFormat format;
764
765
/**
766
* Include test dependencies
767
*/
768
@WithDefault("false")
769
boolean includeTestDependencies;
770
771
enum SbomFormat {
772
SPDX, CYCLONEDX
773
}
774
}
775
```
776
777
**Usage Example:**
778
779
```java
780
@BuildStep(onlyIf = SbomEnabled.class)
781
void generateSbom(ApplicationArchivesBuildItem archives,
782
SbomConfig sbomConfig,
783
BuildProducer<GeneratedResourceBuildItem> resources) throws IOException {
784
785
SbomGenerator generator = SbomGenerator.create(sbomConfig.format);
786
787
// Add application information
788
generator.addComponent("application",
789
archives.getRootArchive().getKey().toString(),
790
"1.0.0");
791
792
// Add dependencies
793
for (ApplicationArchive archive : archives.getApplicationArchives()) {
794
ResolvedDependency dep = archive.getResolvedDependency();
795
generator.addDependency(
796
dep.getGroupId() + ":" + dep.getArtifactId(),
797
dep.getVersion(),
798
"library"
799
);
800
}
801
802
// Generate SBOM file
803
String sbomContent = generator.generate();
804
String filename = "sbom." + sbomConfig.format.name().toLowerCase();
805
806
resources.produce(new GeneratedResourceBuildItem(
807
"META-INF/" + filename,
808
sbomContent.getBytes(StandardCharsets.UTF_8)
809
));
810
}
811
```