How do you run a Spring Boot application locally with the Maven or Gradle plugin, and what do those plugins add over a plain build?
answer
- mvn spring-boot:run / ./gradlew bootRun for dev
- repackage / bootJar make the fat jar
- dependencies nested in BOOT-INF/lib
- plain jar isn't runnable standalone
- java -jar just works after packaging
basics
~20 sWith Maven run mvn spring-boot:run; with Gradle run ./gradlew bootRun. Both compile and start your @SpringBootApplication main class in dev. The plugins also build an executable jar containing all dependencies so java -jar just works.
solid answer
~40 sThe Spring Boot plugins do two main jobs. For local dev, `mvn spring-boot:run` (the `run` goal) and Gradle's `bootRun` task compile your code, put it on the classpath, and launch your `@SpringBootApplication` main method, with fast restart via devtools if present. For packaging, `mvn package` triggers the `repackage` goal and `./gradlew bootJar` produces a single self-contained executable jar (a 'fat' or 'uber' jar) that nests every dependency plus a launcher, so `java -jar app.jar` starts the whole app with no external classpath. Without the plugin you'd get an ordinary jar with only your classes, which won't run standalone because its dependencies are missing. You typically use `spring-boot:run`/`bootRun` while coding and the packaged jar for CI, Docker, and deployment.
code
java · 16 lines// The class the plugins launch — annotated with @SpringBootApplication
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
// Dev loop: mvn spring-boot:run OR ./gradlew bootRun
// Package: mvn package OR ./gradlew bootJar
// Then run: java -jar target/demo-0.0.1-SNAPSHOT.jargo deeper
Must know the two commands (spring-boot:run / bootRun) and that packaging creates a runnable fat jar.
Should explain repackage/bootJar producing the executable jar and the forked-JVM detail of spring-boot:run.
Frames dev-loop vs deploy-artifact tradeoffs and nested-jar vs shaded-jar rationale.
Ties build-plugin choices to CI/CD, container layering, and reproducible artifacts strategy.
**The build plugins.** Spring Boot ships a Maven plugin (`spring-boot-maven-plugin`) and a Gradle plugin (`org.springframework.boot`). They exist because a normal Java build produces a jar containing *only your compiled classes* — it does not include the third-party libraries your app needs, so `java -jar` on it fails with `NoClassDefFoundError`. The plugins solve two problems: running the app during development, and packaging a runnable artifact. **Running locally.** - *Maven:* `mvn spring-boot:run` invokes the plugin's `run` goal. It resolves the project classpath, then starts your class annotated with `@SpringBootApplication` (the one whose `main` calls `SpringApplication.run(...)`). By default it forks a separate JVM so plugin JVM args don't leak into your app. - *Gradle:* `./gradlew bootRun` runs the `BootRun` task, which does the equivalent — builds, then runs the main class. Both are for the *dev inner loop*: edit, run, test. If `spring-boot-devtools` is on the classpath you also get automatic restart on file changes. **Packaging (the executable jar).** When you run `mvn package`, the plugin's `repackage` goal (bound to the `package` phase by default) takes the plain jar that `maven-jar-plugin` just built and rewrites it into an *executable* jar: it nests all dependency jars under `BOOT-INF/lib/`, your classes under `BOOT-INF/classes/`, adds Spring Boot's loader classes, and sets the manifest so `Main-Class` points at a launcher and `Start-Class` points at your app. In Gradle the `bootJar` task does the same thing directly. The result is a single file you can ship and run with `java -jar target/app.jar`. **Why nested jars, not a merged jar.** Spring Boot keeps each dependency jar intact inside the archive (nested), rather than exploding all classes into one flat namespace (as a 'shaded'/uber jar would). This avoids resource/file collisions between libraries and preserves signatures; a custom classloader in Spring Boot's loader reads the nested jars at runtime. **When to use which.** Use `spring-boot:run`/`bootRun` for local development; use the packaged jar (`mvn package` / `./gradlew bootJar`) for anything you deploy — Docker images, servers, CI artifacts. **Gotchas.** - `spring-boot:run` forks a JVM by default, so `MAVEN_OPTS` doesn't affect the app; pass args via the plugin's `jvmArguments`/`arguments` config or `-Dspring-boot.run.jvmArguments`. - The plain jar alone is not runnable — that's expected; you need the repackaged/bootJar artifact. - `bootRun` and `bootJar` are separate tasks; running one does not produce the other.
- Why can't you just run the jar produced by `maven-jar-plugin` without the Spring Boot plugin?That jar contains only your compiled classes, not your dependencies, and its manifest has no runnable launcher. Running it fails because required library classes are missing from the classpath.
- How do you pass a Spring profile or JVM arg when using spring-boot:run or bootRun?Maven: `mvn spring-boot:run -Dspring-boot.run.profiles=dev` or `-Dspring-boot.run.jvmArguments="-Xmx512m"`. Gradle: `./gradlew bootRun --args='--spring.profiles.active=dev'` or configure the bootRun task's `jvmArgs`.
saying these in an interview costs you the question
- Claiming the plain maven-jar-plugin jar is runnable with java -jar
- Thinking spring-boot:run and repackage are the same goal
- Believing bootRun automatically produces the bootJar artifact