Slow Spring Boot startup time wastes developer productivity and increases Kubernetes pod restart time. Learn the techniques that cut startup time by 60-80% with real benchmarks.
JOptimize Team
A Spring Boot application that takes 8 seconds to start isn't just slow in development - it's a liability in production. Kubernetes readiness probes fail. Rolling deployments stall. Autoscaling lags. In this guide, we cut startup time by 60-80% using techniques that require no architectural changes.
Before optimizing, know your baseline. Enable Spring Boot's startup actuator:
# application.properties spring.jmx.enabled=false spring.output.ansi.enabled=never
Get a startup breakdown:
java -Dspring.startup.jmx.enabled=true \ -Dspring.startup.report.enabled=true \ -jar app.jar
Or use the ApplicationStartup API to trace bean initialization:
@SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication app = new SpringApplication(Application.class); app.setApplicationStartup(new BufferingApplicationStartup(2048)); app.run(args); } }
Then call GET /actuator/startup to see which beans take longest to initialize.
By default, Spring initializes all beans at startup. Enable lazy initialization to defer bean creation until first use:
spring.main.lazy-initialization=true
Impact: 20-40% startup reduction for typical apps. Beans are initialized on first request instead.
Caveat: Configuration errors surface at runtime, not startup. Add validation at key entry points:
@Component public class CriticalServiceValidator implements ApplicationRunner { @Autowired private DataSource dataSource; @Override public void run(ApplicationArguments args) throws Exception { // Force critical beans to initialize eagerly even with lazy=true dataSource.getConnection().close(); } }
Spring Boot auto-configures dozens of features you may not need. Exclude them explicitly:
@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class, // If not using JPA SecurityAutoConfiguration.class, // If handling security manually ManagementWebSecurityAutoConfiguration.class, JmxAutoConfiguration.class, TaskExecutionAutoConfiguration.class // If not using @Async }) public class Application { ... }
Or via properties:
spring.autoconfigure.exclude=\ org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration,\ org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration
To find what's being auto-configured:
java -Ddebug=true -jar app.jar 2>&1 | grep "Positive matches"
CDS pre-processes JDK classes into a shared archive, reducing class loading time on every restart:
# Step 1: Generate the CDS archive (run once) java -Xshare:dump # Step 2: Create app-specific archive java -XX:ArchiveClassesAtExit=app-cds.jsa \ -Dspring.context.exit=onRefresh \ -jar app.jar # Step 3: Use the archive on every startup java -XX:SharedArchiveFile=app-cds.jsa \ -jar app.jar
Spring Boot 3.3+ supports CDS out of the box:
# With Spring Boot's CDS support mvn spring-boot:process-aot java -Dspring.aot.enabled=true \ -XX:SharedArchiveFile=application.jsa \ -jar app.jar
Impact: 15-30% startup reduction. Works with any JDK 17+.
Spring Boot 3.x can pre-compute bean definitions, proxy classes, and configuration at build time instead of runtime:
<!-- pom.xml - already included in spring-boot-maven-plugin --> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <executions> <execution> <goals> <goal>process-aot</goal> </goals> </execution> </executions> </plugin>
mvn spring-boot:process-aot package java -Dspring.aot.enabled=true -jar app.jar
Impact: 20-35% startup reduction. Required for GraalVM native image.
For the maximum startup gain, compile to a native binary. Startup drops from seconds to milliseconds:
<plugin> <groupId>org.graalvm.buildtools</groupId> <artifactId>native-maven-plugin</artifactId> </plugin>
mvn -Pnative native:compile ./target/app # Starts in ~80ms
Before/after benchmarks (typical REST API):
| Technique | Startup Time | Memory |
|---|---|---|
| Baseline JVM | 8.2s | 320MB |
| Lazy init | 5.1s | 310MB |
| + Exclude auto-configs | 4.2s | 300MB |
| + CDS | 3.1s | 300MB |
| + AOT | 2.4s | 290MB |
| GraalVM native | 0.08s | 75MB |
# application.properties - apply these first spring.main.lazy-initialization=true spring.jmx.enabled=false spring.main.banner-mode=off logging.level.root=WARN # Reduce log output at startup
# JVM flags for faster startup java -XX:TieredStopAtLevel=1 \ # Skip JIT optimization at startup (dev only) -noverify \ # Skip bytecode verification (dev only) -jar app.jar
-noverify in production - skipping bytecode verification is a security risk; only use in developmentSpring Boot startup optimization starts with lazy initialization and auto-config exclusion (quick, zero-risk wins), then CDS and AOT for bigger gains, and GraalVM native for the maximum reduction. Apply them incrementally and measure after each step. A typical REST API goes from 8s to under 2s with just the first three techniques.
JOptimize analyzes your Spring Boot configuration for startup anti-patterns - eager bean initialization, unused auto-configurations, and missing AOT hints - and ranks them by startup impact.
Cut your Spring Boot startup time before slow pod restarts become a production incident - free scan, no configuration required.
Master Spring Boot, security, and Java performance with hands-on courses.
JOptimize finds N+1 queries, EAGER collections, and 70+ other issues in your Java codebase — in under 30 seconds.