skip to content

When is the built-in application plugin the right choice versus a framework launcher like Spring Boot's bootRun, and what are common ways teams misuse it?

level: seniorimportance: should knowfreq 30%

answer

  1. application plugin = plain main()-owning apps
  2. Spring Boot → bootRun + bootJar instead
  3. plain jar is NOT executable (no Main-Class, no deps)
  4. intended artifact = distribution, not a fat jar
  5. don't apply two competing launchers

basics

~20 s

Use the application plugin for plain executable JVM apps where you control main(). Frameworks like Spring Boot provide their own bootRun task and packaging, so you usually rely on those instead. Misuse: forcing both, or expecting application to build an executable fat jar.

solid answer

~40 s

The `application` plugin is ideal for a self-contained JVM program where you own `main()` and want a standard `run` task plus simple distribution. For framework apps, the framework typically supplies a richer launcher: Spring Boot's plugin adds `bootRun` (with devtools/restart awareness) and `bootJar` (an executable, layered fat jar). In that world you generally do not also rely on the `application` plugin's `run`. Key misconceptions: (1) the application plugin does **not** produce an executable/fat jar — its plain `jar` lacks a `Main-Class` manifest and bundled dependencies, so `java -jar` fails; you need a fat-jar plugin or distribution for that. (2) Applying both Spring Boot and `application` can create two competing entry-point configs. Choose one launcher and one packaging strategy per app, and let `mainClass` be the single source of truth.

code

bash · 7 lines
bash
# application plugin's plain jar is NOT runnable:
./gradlew jar
java -jar build/libs/app.jar
# -> no main manifest attribute, in build/libs/app.jar

# the application plugin's intended runnable form is the distribution
# (start script + lib/ of deps), or use a fat-jar plugin for one jar.

go deeper

for a junior

Know the plugin is for plain runnable apps and that the jar isn't directly executable.

for a middle

Contrast it with bootRun/bootJar and explain why the plain jar can't be java -jar'd.

for a senior

Give a clear decision guide and call out the dual-launcher and fat-jar misconceptions.

for a principal

Set org-wide conventions for run/package strategy per stack and prevent competing launcher/packaging setups in convention plugins.

## What the application plugin is good at For a plain JVM program — a CLI tool, a small service with a hand-written `main()` — the application plugin is the clean choice: one `run` task, `mainClass` as the entry point, `applicationDefaultJvmArgs` for tuning, and built-in distribution. No framework, no magic. ## Where frameworks take over Application frameworks ship their own Gradle integration: - **Spring Boot** adds `bootRun` (knows about devtools, optional restart, system-property forwarding) and `bootJar` (an executable, *layered* fat jar with a launcher and nested dependency jars). - Other frameworks (Micronaut, Quarkus, Ktor) similarly provide tailored run/package tasks. In these stacks the framework's tasks are the supported path. Spring Boot still reads `mainClass` (often via its own `springBoot { mainClass }` or auto-detection), but you drive runs through `bootRun`, not the application plugin's `run`. ## The big misconception: application ≠ fat jar The application plugin's `jar` task produces an ordinary library jar: - no `Main-Class` in the manifest by default, - no bundled dependencies. So `java -jar build/libs/app.jar` throws `no main manifest attribute` (or `NoClassDefFoundError`). The application plugin's *intended* artifact is the **distribution** (install/zip) that ships a start script plus a `lib/` of dependency jars — not a single runnable jar. If you genuinely need one self-contained executable jar, that is a fat/uber-jar plugin's job, not this plugin's. ## Common misuse patterns 1. **Applying both Spring Boot and `application`** and being surprised by two entry-point mechanisms or duplicate run tasks. Pick one. 2. **Expecting `./gradlew jar` to yield a runnable jar.** It does not. 3. **Clobbering the run classpath** (covered elsewhere) so deps go missing. 4. **Hardcoding JVM tuning in CI scripts** instead of `applicationDefaultJvmArgs`, so local and CI diverge. ## Decision guide - Hand-written `main()`, no framework launcher → application plugin. - Spring Boot / Micronaut / Quarkus → use the framework's run + package tasks. - Need one portable executable jar → fat-jar tooling, regardless of which run task you use.

  • Why does java -jar on the application plugin's jar fail?
    The plain jar task does not add a Main-Class manifest entry and does not bundle dependencies. The plugin's runnable artifact is the distribution with a start script, not a self-contained jar. For one runnable jar you need fat-jar tooling.
  • If you use Spring Boot, do you still set mainClass on the application extension?
    Usually you let Spring Boot detect or configure the main class via its own DSL, and you run via bootRun. Mixing the application plugin's run with bootRun creates two entry-point paths; standardize on the framework's.

The application plugin gives you a car with a standard ignition (run) and a tow-package (distribution). Spring Boot hands you a whole different vehicle with its own keyless start (bootRun) and a sealed all-in-one chassis (bootJar) — bolting both ignitions onto one car just confuses the driver.

saying these in an interview costs you the question

  • Claiming ./gradlew jar produces an executable fat jar.
  • Recommending applying both Spring Boot and application for the run task.
  • Saying the application plugin bundles dependencies into the jar.

context