What does the Shadow plugin's shadowJar task produce, and why would you reach for it instead of the standard jar task?
answer
- single self-contained jar
- bundles runtimeClasspath
- java -jar app-all.jar
- com.gradleup.shadow
- -all classifier
basics
~10 sshadowJar builds a single 'fat'/'uber' jar that bundles your compiled classes plus all runtime dependencies, so the app can run with java -jar alone — the standard jar only contains your own classes.
solid answer
~40 sThe Shadow plugin (`com.gradleup.shadow`, formerly `com.github.johnrengelman.shadow`) adds a `shadowJar` task that produces an **uber jar** (a.k.a. fat jar): it unpacks every dependency on the `runtimeClasspath` and merges those class files together with your own compiled output into one self-contained archive. The plain `jar` task only packages the module's own classes and points at dependencies via the manifest classpath, so it needs the dependency jars present at runtime. A fat jar is convenient for deployment and simple `java -jar app-all.jar` execution — no external classpath, no lib folder. By default Shadow names the artifact with an `-all` classifier and wires the main class into the manifest when the Application plugin is applied. Trade-offs: larger artifact, potential file collisions across dependencies, and licensing considerations from bundling third-party code.
code
kotlin · 8 linesplugins {
application
id("com.gradleup.shadow") version "8.3.0"
}
application { mainClass = "com.example.MainKt" }
// ./gradlew shadowJar -> build/libs/app-1.0-all.jar (runnable)go deeper
Know that shadowJar makes one runnable jar with all dependencies inside, runnable via java -jar.
Explain the runtimeClasspath flattening, the -all classifier, and app vs library trade-offs.
Discuss collisions, transformers, and why fat jars hurt library publishing; mention the gradleup coordinate migration.
Frame fat-jar usage as a packaging/distribution policy decision across services vs. libraries, with size, licensing, and reproducibility implications.
## What an uber/fat jar is A normal JAR built by Gradle's `jar` task contains only the classes and resources compiled from **your** module. At runtime the JVM still needs every third-party dependency on the classpath; you supply them via `-cp`, a `lib/` directory, or a `Class-Path` manifest entry. That's awkward for distributing a single runnable artifact. An **uber jar** (also called a **fat jar** or **shaded jar**) flattens everything into one archive: your classes **plus** the unpacked contents of every dependency JAR on `runtimeClasspath`. The result runs with nothing but `java -jar app-all.jar`. ## The Shadow plugin Shadow is the de-facto Gradle plugin for this. Historically it was `com.github.johnrengelman.shadow`; maintenance moved to the GradleUp org and the modern coordinate is **`com.gradleup.shadow`**. Applying it adds a `shadowJar` task of type `ShadowJar` (a subtype of Gradle's `Jar`). ```kotlin plugins { application id("com.gradleup.shadow") version "8.3.0" } application { mainClass = "com.example.MainKt" } ``` Running `./gradlew shadowJar` produces `build/libs/<name>-<version>-all.jar`. ## How it differs from `jar` | | `jar` | `shadowJar` | |---|---|---| | Contents | own classes only | own classes + all runtime deps | | Runnable standalone | no | yes | | Size | small | large | | Collisions | none | possible (handled by merge strategies) | ## What Shadow does under the hood 1. Resolves `configurations.runtimeClasspath`. 2. Unpacks each dependency jar and copies its entries into the output. 3. Applies **transformers** (e.g. `mergeServiceFiles()`) to combine files that would otherwise collide. 4. Optionally **relocates** packages and **minimizes** unused classes. Because `ShadowJar` extends `Jar`, you can use the normal `manifest { }`, `from(...)`, `exclude(...)` DSL on it. ## When NOT to use it Libraries published to a repository should generally publish a thin jar plus POM metadata, not a fat jar — bundling dependencies inside a library breaks downstream dependency resolution and version conflict handling. Fat jars are for **applications** and CLI tools you deploy or hand to users.
- Why is publishing a fat jar as a library generally discouraged?It bundles transitive dependencies inside the artifact, so consumers lose POM-driven dependency resolution and conflict mediation, and can end up with duplicate/incompatible classes. Libraries should publish thin jars with metadata.
- What classifier does Shadow give the output by default and where does it land?It uses the `all` archive classifier, producing `build/libs/<name>-<version>-all.jar` by default.
A normal jar is a recipe card that lists ingredients you must already own; an uber jar is the fully-assembled microwave meal — everything's inside, just heat and eat.
saying these in an interview costs you the question
- Claiming the standard `jar` task already includes dependencies.
- Saying you should always publish libraries as fat jars.