Compare the assembly plugin with the shade plugin and spring-boot-maven-plugin for producing distributable artifacts. When do you pick each?
answer
- assembly = layouts/formats/perms
- shade = relocate + transformers (merge services)
- spring-boot = nested jar + Boot loader
- assembly fat jar overwrites collisions
- Boot app -> never shade/assembly
basics
~20 sAssembly = flexible distribution layouts (zip/tar.gz, bin/lib/conf) and simple fat jars. Shade = uber-jars that need package relocation and proper merging of service files. spring-boot-maven-plugin = runnable Spring Boot jars with nested-jar layout. Pick by what you're shipping.
solid answer
~40 sAll three bundle output but solve different problems. **assembly-plugin** is the general-purpose 'build any distribution' tool: arbitrary directory layouts (bin/lib/conf tarballs), multiple formats, file modes, filtering. Its fat jar (jar-with-dependencies) just merges files and **overwrites collisions**. **shade-plugin** specializes in uber-jars: it can **relocate** (rename) packages to dodge version conflicts, and uses **transformers** (ServicesResourceTransformer, ManifestResourceTransformer, AppendingTransformer) to *merge* META-INF/services, manifests, and config files correctly — essential for SPI-heavy stacks and libraries you republish. **spring-boot-maven-plugin** (`repackage` goal) produces a Boot-specific nested-jar (dependencies kept as jars inside, custom classloader), supporting `java -jar` plus layered images and `executable` scripts. Rule of thumb: Boot app -> spring-boot; library uber-jar / conflict relocation -> shade; OS-style distribution package or simple conflict-free fat jar -> assembly.
code
xml · 16 lines<!-- shade: merge service files + set main class -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<executions><execution><phase>package</phase>
<goals><goal>shade</goal></goals>
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>com.example.Main</mainClass>
</transformer>
</transformers>
</configuration>
</execution></executions>
</plugin>go deeper
Knows all three can bundle dependencies into a deliverable.
Can name what each produces (distribution vs uber-jar vs Boot jar).
Picks correctly based on SPI/relocation/Boot needs and justifies trade-offs.
Sets org-wide packaging standards, combines tools, and reasons about reproducibility, signing, and layered images.
## The three tools at a glance | Concern | assembly-plugin | shade-plugin | spring-boot-maven-plugin | |---|---|---|---| | Primary use | Any distribution archive/layout | Uber-jar with merge + relocation | Runnable Spring Boot app | | Fat jar | yes (jar-with-dependencies) | yes (default) | yes (nested, not flat) | | Custom dir layout (bin/lib/conf) | **yes** | no | no | | Output formats | zip/tar.gz/dir/jar/... | jar | jar/war | | Merges META-INF/services | **no (overwrites)** | **yes (transformers)** | n/a (deps kept as jars) | | Package relocation/shading | no | **yes** | no | | Class layout | flat (unpacked) | flat (unpacked) | nested jars + Boot loader | ## assembly-plugin Best when the **deliverable shape** matters: a tarball with `bin/`, `lib/`, `conf/`, README, executable scripts, multiple formats at once, file permissions, property filtering. Its fat jar is the weakest part — it merges files and lets later jars overwrite earlier ones, which silently breaks SPI/ServiceLoader and signed jars. ## shade-plugin Best for **uber-jars done right**: - **Relocation:** rename a dependency's packages (e.g. shade Guava into `com.myapp.shaded.guava`) so your library doesn't clash with the consumer's version — critical for published libraries. - **Transformers:** `ServicesResourceTransformer` concatenates `META-INF/services/*`; `ManifestResourceTransformer` sets Main-Class; `AppendingTransformer` merges `reference.conf`/properties; signature-removal for signed deps. - Also rewrites the published pom (`dependency-reduced-pom`) so consumers don't double-pull bundled deps. ## spring-boot-maven-plugin Best for **Spring Boot applications**. The `repackage` goal produces a special **nested jar**: dependency jars are stored *as jars* inside `BOOT-INF/lib`, with a custom `JarLauncher` classloader. This avoids the merge/collision problems entirely (no unpacking), supports **layered jars** for efficient Docker caching, build-info, and a `start.sh`-style `executable` mode. Don't use assembly/shade for Boot apps — they break the nested layout. ## Decision guide 1. Spring Boot app? -> **spring-boot-maven-plugin**. 2. Publishing a *library* uber-jar, or you have dependency-version conflicts / SPI files to merge? -> **shade-plugin**. 3. Need an OS-style distribution (tarball, dirs, scripts, configs) or a simple conflict-free CLI fat jar? -> **assembly-plugin**. They can also be combined: e.g. shade to build a correct uber-jar, then assembly to wrap it with config/docs into a tar.gz.
- You publish a library that bundles Guava; consumers complain of version clashes. Which plugin and feature fixes this?shade-plugin with package relocation — rename the bundled Guava packages so they can't collide with the consumer's Guava.
- Why is a Spring Boot fat jar not just a jar-with-dependencies?Boot keeps dependencies as nested jars with a custom classloader (JarLauncher), avoiding class/resource merge collisions and enabling layered images; flat assembly fat jars would break that.
- Can assembly and shade be used together?Yes — shade to build a correct uber-jar, then assembly to wrap it with config, scripts, and docs into a tar.gz distribution.
assembly is a moving company that packs any boxes you want; shade is a specialist that relabels conflicting parts so nothing clashes; spring-boot is the manufacturer's own purpose-built shipping crate.
saying these in an interview costs you the question
- Using assembly's jar-with-dependencies for a library and breaking SPI/relocation (should be shade).
- Using shade or assembly for a Spring Boot app instead of spring-boot-maven-plugin.
- Believing all three are interchangeable fat-jar makers with no behavioral differences.