Question

Disable plain JAR Files in Spring Boot 2.5 with Gradle

kotlinjavaspringspring-bootgradle

Question

After upgrading to Spring Boot 2.5.0, Gradle generates a myprogram-0.0.1-plain.jar file in addition to the usual myprogram-0.0.1.jar file. How can I configure Gradle 7.0.2 not to generate the *-plain.jar file?

Current output:

build/libs/
├── myprogram-0.0.1.jar
└── myprogram-0.0.1-plain.jar

Desired output:

build/libs/
└── myprogram-0.0.1.jar

Current build.gradle:

plugins {
    id 'org.springframework.boot' version '2.5.0'
    id 'io.spring.dependency-management' version '1.0.11.RELEASE'
    id 'java'
}

group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

test {
    useJUnitPlatform()
}

Short Answer

You will learn why Spring Boot creates two JAR files, the difference between an executable Spring Boot JAR and a plain Java JAR, and how to disable the standard Gradle jar task when you only need the executable artifact.

Concept

Gradle's Java plugin provides a standard jar task. It creates a plain JAR containing your compiled classes and resources.

The Spring Boot Gradle plugin adds a bootJar task. It creates an executable JAR that contains:

  • Your application classes
  • Application resources
  • Runtime dependencies
  • Spring Boot launcher classes

Before Spring Boot 2.5, build setups could make both tasks try to use the same output name. In Spring Boot 2.5, the plugin avoids that collision by giving the standard jar task the plain classifier. Therefore, a project named myprogram can produce:

myprogram-0.0.1.jar        executable Spring Boot JAR, produced by bootJar
myprogram-0.0.1-plain.jar  standard Java JAR, produced by jar

If the project is an application that you only run as a Spring Boot service, the plain JAR is often unnecessary. You can disable the jar task and retain only the executable JAR.

This distinction matters because a plain JAR usually cannot be started with java -jar unless it has its own suitable manifest and all dependencies are otherwise available on the classpath. The Spring Boot executable JAR is designed to run directly.

Mental Model

Think of the two artifacts as two kinds of package:

  • The plain JAR is a box containing only your product.
  • The Spring Boot JAR is a ready-to-use kit containing your product, the required parts, and instructions for starting it.

Gradle builds the plain box through jar. Spring Boot builds the ready-to-use kit through bootJar.

Spring Boot 2.5 labels the plain box with -plain so the two packages do not accidentally overwrite each other.

Take Quiz

Syntax and Examples

Disable Gradle's standard jar task in a Groovy build.gradle file:

jar {
    enabled = false
}

Place it after the plugins block, commonly near the end of the build file:

plugins {
    id 'org.springframework.boot' version '2.5.0'
    id 'io.spring.dependency-management' version '1.0.11.RELEASE'
    id 'java'
}

// Other configuration: group, version, repositories, dependencies...

jar {
    enabled = false
}

Then run:

./gradlew build

The bootJar task remains enabled, so Gradle still creates the normal Spring Boot executable artifact:

build/libs/myprogram-0.0.1-SNAPSHOT.jar

You can also use task configuration syntax:

tasks.named('jar') {
    enabled = false
}

Both approaches disable the same standard JAR task. The tasks.named form is especially useful in larger Gradle builds because it configures the task by name without eagerly looking up all tasks.

Step by Step Execution

Consider this configuration:

plugins {
    id 'org.springframework.boot' version '2.5.0'
    id 'java'
}

jar {
    enabled = false
}

When you run the following command:

./gradlew build

Gradle proceeds as follows:

  1. The java plugin creates the standard jar task.
  2. The Spring Boot plugin creates the bootJar task.
  3. Spring Boot configures the regular jar artifact with the plain classifier to prevent a filename conflict.
  4. Your jar { enabled = false } configuration marks the standard jar task as disabled.
  5. The build lifecycle task runs compilation, tests, and artifact tasks it depends on.
  6. Gradle skips the disabled jar task.
  7. Gradle runs bootJar and writes the executable Spring Boot JAR to build/libs.

To inspect the available tasks, run:

./gradlew tasks --all

To build only the runnable application artifact, run:

./gradlew bootJar

Real World Use Cases

  • Web APIs and backend services: A Spring Boot REST API is normally deployed as an executable JAR in a container, virtual machine, or process manager. The plain JAR is not needed.
  • Docker images: A Dockerfile commonly copies one executable JAR into the image. Producing only that artifact prevents ambiguous wildcard copies such as COPY build/libs/*.jar app.jar.
  • CI/CD pipelines: A release pipeline can publish, upload, or scan one known deployable artifact rather than selecting between two JAR files.
  • Scheduled jobs and command-line tools: A Spring Boot batch job can be launched with java -jar, so the executable JAR is the intended output.
  • Library modules: A reusable module is different: it typically needs the standard plain JAR for consumers to add to their classpath. In that case, do not disable jar.
Take Quiz

Real Codebase Usage

In real Gradle projects, application modules usually make the executable artifact explicit and avoid treating every generated file as deployable.

A typical application module configuration is:

plugins {
    id 'org.springframework.boot'
    id 'java'
}

jar {
    enabled = false
}

Teams also commonly build the specific artifact required by deployment:

./gradlew clean bootJar

This avoids relying on incidental outputs from the broader build task.

In a multi-module repository, the decision is made per module:

  • Application module: enable bootJar; usually disable jar.
  • Shared library module: enable jar; usually do not apply the Spring Boot plugin.

If a library module uses Spring Boot dependency management or Spring APIs, it can still publish a normal JAR. It should not automatically be packaged as a runnable application merely because it uses Spring-related dependencies.

Common Mistakes

Deleting the file after every build

Manually deleting *-plain.jar works temporarily, but the next build recreates it. Configure the producing task instead:

jar {
    enabled = false
}

Disabling bootJar instead of jar

This configuration removes the executable Spring Boot artifact, which is usually the opposite of the goal:

// Usually wrong for a deployable Spring Boot application
bootJar {
    enabled = false
}

Use this only when the project is intentionally a library and should not produce an executable Boot JAR.

Assuming the plain JAR is a duplicate

The files contain different layouts and serve different purposes. The plain JAR contains application classes and resources; the Boot JAR also packages runtime dependencies and startup support.

Renaming artifacts to hide the issue

Changing archiveFileName may rename output files, but it does not stop the regular jar task from running. Disable jar when you do not need its artifact.

Disabling jar in a publishable library

If the module is consumed by other projects or published to Maven repositories, disabling jar can leave no normal library artifact to publish. Keep jar enabled for library modules.

Comparisons

Aspectjar taskbootJar task
Main purposePackage a standard Java library/application JARPackage a runnable Spring Boot application
Typical output in Spring Boot 2.5app-version-plain.jarapp-version.jar
Includes runtime dependenciesNoYes, in Spring Boot's executable layout
Normally runnable with java -jarNoYes
Best suited toShared libraries and classpath-based applicationsServices, APIs, jobs, and deployable applications
Disable for a Boot-only app?Usually yesNo

The plain part is a classifier: an extra label Gradle adds to distinguish an artifact from another artifact with the same base name and version.

Take Quiz

Cheat Sheet

// Disable the standard Java JAR task.
jar {
    enabled = false
}
// Equivalent lazy task configuration.
tasks.named('jar') {
    enabled = false
}
# Build only the executable Spring Boot JAR.
./gradlew bootJar

# Run all normal build checks and produce configured artifacts.
./gradlew build
  • jar creates the standard Java JAR.
  • bootJar creates the executable Spring Boot JAR.
  • Spring Boot 2.5 uses the plain classifier for the standard JAR to avoid filename collisions.
  • Disable jar for an application-only module when only the Boot artifact is required.
  • Keep jar enabled when the module is a reusable or published library.

FAQ

Why does Spring Boot 2.5 create a -plain.jar file?

Spring Boot 2.5 distinguishes the standard Gradle jar output from the executable bootJar output. The plain classifier prevents both tasks from generating files with the same name.

Can I safely delete the plain JAR file?

You can delete it, but it will return on the next build. Disable the Gradle jar task if your application never needs the file.

What Gradle configuration removes the plain JAR?

Add this to build.gradle:

jar {
    enabled = false
}

Will disabling jar stop my Spring Boot application from building?

No. The Spring Boot executable artifact is produced by bootJar, not the standard jar task.

Which JAR should I deploy to run a Spring Boot application?

Deploy the JAR without the -plain suffix, unless your build has been customized to use different names. It is normally the executable Spring Boot JAR.

Should a shared library disable the jar task?

No. Shared libraries generally need the normal JAR so other applications can depend on and use them.

Can I build the executable artifact without running the whole build lifecycle?

Yes:

./gradlew bootJar

This directly runs the task that creates the executable Spring Boot JAR.

Take Quiz

Mini Project

Description

Configure a small Spring Boot application so its Gradle build produces only the executable application JAR. This mirrors a deployment-oriented service where a CI pipeline or Docker image needs one unambiguous artifact.

Goal

Build the application and verify that build/libs contains the executable Spring Boot JAR but no -plain.jar file.

Requirements

  1. Create or use a Spring Boot project that applies the java and org.springframework.boot plugins.
  2. Keep the Spring Boot executable JAR enabled.
  3. Disable the standard Gradle jar task.
  4. Run the Gradle build task.
  5. Verify that no file ending in -plain.jar is generated in build/libs.
Take Quiz

Keep learning

Related questions

View more