skip to content

What is the `classifier` configuration in the Spring Boot build plugins, and when would you set one?

level: seniorimportance: should knowfreq 45%

answer

  1. classifier = suffix on same coordinates
  2. default: fat jar replaces plain (.original backup)
  3. set 'exec' -> plain stays main, fat attached
  4. needed when module is app AND library
  5. Gradle 2.5+ plain jar gets '-plain' classifier

basics

~20 s

By default the executable jar replaces the plain jar under the same coordinates. Setting a classifier (e.g. exec) gives the executable jar a suffixed name so both the plain library jar and the executable jar are kept and can be published side by side.

solid answer

~40 s

A Maven/Gradle `classifier` is a suffix on an artifact's coordinates (e.g. `app-1.0-exec.jar`) that lets multiple artifacts share the same groupId/artifactId/version. By default Spring Boot's `repackage`/`bootJar` makes the executable jar the *main* artifact — it overwrites the plain jar (Maven saves the plain one as `.original`). If you set `<classifier>exec</classifier>` in Maven, the executable jar is attached under that classifier and the *plain* jar remains the main artifact. This matters when a module is both a runnable app and a library other modules depend on: consumers get the lean plain jar via normal coordinates, while the executable jar is published separately as `...-exec.jar`. In Gradle you achieve the split via the `bootJar` task's `archiveClassifier` (and re-enabling the plain `jar`). Without it, publishing the fat jar as a dependency drags every nested dependency into consumers.

code

java · 14 lines
java
// Maven: keep the plain jar as the MAIN artifact, attach the executable one.
//
// <plugin>
//   <groupId>org.springframework.boot</groupId>
//   <artifactId>spring-boot-maven-plugin</artifactId>
//   <configuration>
//     <classifier>exec</classifier>
//   </configuration>
// </plugin>
//
// Produces:
//   target/app-1.0.jar        -> plain library jar (main artifact; consumers resolve this)
//   target/app-1.0-exec.jar   -> executable fat jar (run with java -jar)
public class ClassifierNotes { }

go deeper

for a junior

May not know classifier exists; fine to just know default replaces the plain jar.

for a middle

Understands classifier suffixes and the .original backup.

for a senior

Must explain the app-and-library conflict and configure classifier to keep the plain jar as main artifact.

for a principal

Owns publication strategy so shared modules never leak fat jars into consumers' classpaths.

**What a classifier is.** In Maven/Gradle coordinates `groupId:artifactId:version[:classifier]`, the *classifier* is an optional suffix that distinguishes multiple artifacts built from the same project — e.g. `-sources`, `-javadoc`, or a custom `-exec`. Files are named `artifactId-version-classifier.jar`. **Default Spring Boot behavior (no classifier).** The `repackage` goal replaces the project's main jar with the executable (fat) jar under the *same* name, and stores the pre-repackage plain jar as `target/<name>.jar.original`. So the artifact your build installs/deploys to a repository is the fat, self-contained one. For a pure application this is exactly what you want. **The problem it causes.** If the same module is *also* used as a compile dependency by another module, publishing the fat jar is bad: the consumer would pull in a jar with all of your app's dependencies nested inside `BOOT-INF/lib`, which is not resolvable as normal transitive dependencies and bloats/pollutes their classpath. You want the consumer to get the *plain* library jar. **Setting a classifier (Maven).** Configuring the plugin with `<classifier>exec</classifier>` changes the split: - The executable jar is *attached* as a secondary artifact named `app-1.0-exec.jar` (classifier `exec`). - The plain jar keeps the *main* coordinates `app-1.0.jar` and is the artifact consumers resolve by default. Now both are published: libraries depend on the main plain jar; your deployment pipeline grabs the `exec` classified jar to run. **Gradle equivalent.** In Gradle the split is expressed via task classifiers. Since Spring Boot 2.5, applying the plugin keeps the standard `jar` task enabled but gives its output the `plain` classifier by convention, so you get both `app-plain.jar` (from `jar`) and `app.jar` (from `bootJar`). You can customize with `bootJar { archiveClassifier = 'boot' }` or `jar { archiveClassifier = '' }`. To publish the plain jar as the library artifact and the boot jar separately, you configure the publication accordingly. **When to set a classifier.** - The module is both runnable and a shared library. (Set one.) - You want to publish a plain jar for tooling/IDE indexing while still deploying an executable jar. (Set one.) - Pure leaf application, nothing depends on it → default is fine, no classifier needed. **Gotchas.** - Forgetting the classifier and then depending on the module drags the fat jar into other builds — a common real-world pollution bug. - The `.original` file is Maven-only default behavior; it's not a published artifact by itself. - In Gradle 2.5+ people are surprised to see two jars (`-plain` + boot); that's the plain-classifier convention, not a bug. To suppress the plain jar entirely, disable the `jar` task.

  • You set no classifier and another module depends on this app. What goes wrong?
    The consumer resolves the fat executable jar as its dependency, pulling in every nested library under BOOT-INF/lib. Those aren't normal transitive deps, so the classpath is bloated/polluted and compilation against them can fail. Use a classifier so the plain jar stays the main artifact.
  • In Gradle 2.5+ you see both `app.jar` and `app-plain.jar` — why?
    The plugin keeps the standard `jar` task enabled but gives its plain output the `plain` classifier by convention, while `bootJar` produces the executable `app.jar`. To emit only the boot jar, disable the `jar` task.

saying these in an interview costs you the question

  • Thinking a classifier changes the jar's contents rather than its coordinates/name
  • Believing the fat jar is a good compile dependency for other modules
  • Assuming the .original file is what gets published to the repository

context