What does the maven-assembly-plugin do, and when would you reach for it instead of the default jar packaging?
answer
- single goal -> bind to package
- descriptorRef vs custom assembly.xml
- fat jar = jar-with-dependencies
- formats: zip/tar.gz/dir/jar
- ships dependencies + extra files
basics
~20 sThe assembly plugin bundles your project output plus extra files (dependencies, scripts, docs) into a single distributable archive like a zip, tar.gz, or a fat jar. The default jar packaging only packs your own compiled classes.
solid answer
~40 sThe maven-assembly-plugin builds a custom distribution archive from your project: compiled classes, dependencies, license files, scripts, config — assembled into a single artifact such as a zip, tar.gz, dir, or an executable 'fat jar'. The default `jar` packaging only produces a jar of your own classes, with dependencies left external. You reach for assembly when you need a self-contained deliverable: a runnable jar-with-dependencies for a small tool, or a `bin`-style distribution layout (lib/, bin/, README) for an app you hand to ops. You drive it either with a built-in `descriptorRef` (`jar-with-dependencies`, `bin`, `src`, `project`) or a custom `assembly.xml` descriptor, and bind its single goal `single` to a phase (usually `package`). For runnable Spring Boot apps you'd normally use spring-boot-maven-plugin instead.
code
bash · 3 linesmvn package
# produces target/myapp-1.0-jar-with-dependencies.jar
java -jar target/myapp-1.0-jar-with-dependencies.jargo deeper
Know it packs your app + dependencies into one distributable like a zip or fat jar.
Know the single goal, descriptorRefs (jar-with-dependencies, bin), and binding to package.
Choose assembly vs shade vs spring-boot-maven-plugin appropriately and justify it.
Standardize distribution conventions across modules; decide org-wide packaging strategy and avoid uber-jar pitfalls.
## What it is Maven's default build produces one artifact per module — for `<packaging>jar</packaging>` that is a jar containing **only your project's own compiled classes and resources**. Your dependencies are *not* inside it; at runtime they're resolved from the local repository or a classpath. That's fine for a library, but useless when you want to *ship* something a user can unzip and run. The **maven-assembly-plugin** solves this: it gathers your build output **plus arbitrary other content** (project dependencies, files, directories, scripts, license text) and packs them into one or more **distribution archives**. ## The single goal The plugin effectively has one goal you use: **`assembly:single`**. (The older `assembly:assembly` and `directory` goals are deprecated.) You typically bind `single` to the `package` phase so the archive is built during a normal `mvn package`. ## Two ways to describe the assembly 1. **Predefined `descriptorRefs`** — ready-made recipes shipped with the plugin: - `jar-with-dependencies` — a single 'fat'/'uber' jar containing your classes **and** all dependencies unpacked into it. - `bin` — a typical binary distribution: your main artifact + README/LICENSE/NOTICE at the root. - `src` — a source distribution of the project. - `project` — the whole project directory tree minus build output. 2. **Custom `descriptors`** — you point at your own `assembly.xml` file (commonly `src/main/assembly/`) and control everything: `<formats>`, `<fileSets>`, `<dependencySets>`, `<files>`, directory layout, file permissions, and whether the assembled name has a base directory. ## Output formats The `<formats>` element (or the descriptorRef's defaults) decides what is produced — you can produce several at once: - `zip`, `tar.gz`, `tar.bz2`, `tar` — archive files - `jar` / `war` — jar-style archives - `dir` — an exploded directory (no compression), handy for local inspection ## Minimal example (fat jar) ```xml <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-assembly-plugin</artifactId> <version>3.7.1</version> <configuration> <descriptorRefs> <descriptorRef>jar-with-dependencies</descriptorRef> </descriptorRefs> <archive> <manifest><mainClass>com.example.Main</mainClass></manifest> </archive> </configuration> <executions> <execution> <id>make-assembly</id> <phase>package</phase> <goals><goal>single</goal></goals> </execution> </executions> </plugin> ``` This yields `target/<artifactId>-<version>-jar-with-dependencies.jar`, runnable via `java -jar`. ## When NOT to use it For Spring Boot apps use **spring-boot-maven-plugin** (proper nested-jar layout). For uber-jars that need class relocation/shading use **maven-shade-plugin**. Assembly is best for *distribution layouts* (bin/lib/conf trees, tarballs) and simple fat jars.
- What is the difference between jar-with-dependencies (assembly) and the shade plugin?Both make uber-jars, but assembly just merges files; shade can relocate (rename) packages to avoid dependency conflicts and properly merges service files (META-INF/services). For Spring Boot, use neither — use spring-boot-maven-plugin.
- Which phase do you normally bind assembly:single to and why?package — so the archive is built after the project's own jar/war exists, as part of a normal build, and gets attached for install/deploy.
Default jar = just your code in a box. Assembly = a full shipping crate with your box, all the parts it needs, the manual, and the packing slip.
saying these in an interview costs you the question
- Saying the assembly plugin replaces the default jar — it adds an extra archive alongside it.
- Claiming jar-with-dependencies relocates/renames conflicting packages (that's shade, not assembly).
- Using assembly to build a runnable Spring Boot jar instead of spring-boot-maven-plugin.