skip to content

Compare the assembly plugin with the shade plugin and spring-boot-maven-plugin for producing distributable artifacts. When do you pick each?

level: principalimportance: should knowfreq 30%

answer

  1. assembly = layouts/formats/perms
  2. shade = relocate + transformers (merge services)
  3. spring-boot = nested jar + Boot loader
  4. assembly fat jar overwrites collisions
  5. Boot app -> never shade/assembly

basics

~20 s

Assembly = 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 s

All 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
xml
<!-- 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

for a junior

Knows all three can bundle dependencies into a deliverable.

for a middle

Can name what each produces (distribution vs uber-jar vs Boot jar).

for a senior

Picks correctly based on SPI/relocation/Boot needs and justifies trade-offs.

for a principal

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.

context