Maven
Spring Boot
Java
Application Deployment
Command Line

mvn spring-bootrun vs java -jar

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

Introduction

mvn spring-boot:run and java -jar both start a Spring Boot application, but they are not interchangeable in practice. The Maven command is optimized for local development speed. The JAR command is optimized for running the packaged artifact that will actually be deployed. Treating them as equivalent often hides packaging and classpath issues until very late.

spring-boot:run Uses the Maven Project Classpath

When you run with Maven, Spring Boot starts from the project’s build and dependency context rather than from a packaged JAR file.

bash
mvn spring-boot:run -Dspring-boot.run.profiles=dev

This is convenient because:

  • you do not need to package first,
  • local debugging is fast,
  • and Maven plugin arguments integrate naturally with a development workflow.

That makes it a good command for day-to-day coding.

java -jar Runs the Real Artifact

Running with java -jar means you are testing the executable JAR that the build produced.

bash
mvn clean package
java -jar target/app-1.0.0.jar --spring.profiles.active=prod

This is closer to what production and container environments actually do. It validates the packaged artifact, embedded dependencies, resource layout, and startup path the way deployment will see them.

That is why java -jar is the important smoke test before release, even if developers spend most of their day with spring-boot:run.

Classpath and Resource Behavior Can Differ

Many subtle bugs appear only after packaging. Examples include:

  • resource loading code that assumes files exist directly on disk,
  • classpath assumptions that work in source mode but not from a JAR,
  • or plugin-driven behavior that never exercised the packaged artifact.

So the difference is not philosophical. The startup mode can genuinely reveal different failures.

Profiles and Arguments Should Be Compared Fairly

A lot of “this works in one mode but not the other” confusion comes from giving the two modes different arguments.

bash
1mvn spring-boot:run \
2  -Dspring-boot.run.arguments="--spring.config.location=file:./config/application-dev.yml"
3
4java -jar target/app-1.0.0.jar \
5  --spring.config.location=file:./config/application-dev.yml

If the profiles or config locations differ, you are not really comparing run modes. You are comparing two different applications.

A Practical Workflow Uses Both Commands

A sensible development and delivery workflow usually looks like this:

  1. use spring-boot:run for rapid local edits and debugging,
  2. run tests,
  3. package the JAR,
  4. smoke-test with java -jar,
  5. then build or deploy from that artifact.

Example smoke test:

bash
1mvn -q clean test package
2java -jar target/app-1.0.0.jar --spring.profiles.active=test &
3APP_PID=$!
4sleep 8
5curl -f http://localhost:8080/actuator/health
6kill "$APP_PID"

This catches artifact-specific failures before they reach a container or environment.

Containers Usually Use java -jar

This is one of the clearest operational differences. Production containers almost always run the packaged artifact, not the Maven plugin.

dockerfile
FROM eclipse-temurin:21-jre
COPY target/app-1.0.0.jar /app/app.jar
ENTRYPOINT ["java", "-jar", "/app/app.jar"]

So if the container path matters, validating only with spring-boot:run is not enough.

JVM Flags Matter Too

If you compare startup speed or memory behavior across the two modes, keep JVM settings aligned.

bash
java -Xms256m -Xmx512m -jar target/app-1.0.0.jar

If one run uses different memory settings, GC settings, or profile values, performance conclusions become unreliable.

Common Pitfalls

  • Assuming spring-boot:run is an exact substitute for running the packaged artifact.
  • Skipping java -jar smoke tests and discovering packaging issues only after deployment.
  • Comparing the two modes with different profiles or configuration arguments.
  • Using source-mode success as proof that the containerized runtime path is correct.
  • Drawing performance conclusions when JVM flags differ between the two runs.

Summary

  • 'mvn spring-boot:run is best for local development speed.'
  • 'java -jar is best for artifact fidelity and deployment parity.'
  • The two modes can differ in classpath and resource behavior.
  • A healthy workflow uses both, at different stages.
  • Always validate the packaged JAR before shipping or containerizing it.

Related reading
Course
Beginner
27 lessons
10 hours
System Design Fundamentals

Build a strong foundation in designing scalable, reliable distributed systems.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

All Rights Reserved.