Blog
February 27, 2026
Spring Boot applications are known for their developer-friendly auto-configuration and embedded servers that streamline the development process. Unfortunately, these conveniences often come at the cost of longer startup times and increased resource consumption. As your application grows in complexity, performance bottlenecks can emerge.
In this blog, we'll outline proven strategies for enhancing Spring Boot performance and share actionable troubleshooting techniques to keep your applications running efficiently in production environments.
Need help now? Talk to an OpenLogic expert
Improving Spring Boot Performance
Spring Boot makes it easy to get applications up and running fast. However, as applications grow, dependencies multiply, traffic increases, and infrastructure becomes more distributed, you may start to see slower startup times, memory pressure, long GC pauses, and other issues that negatively impact user experience and drive up operational costs.
The good news: most Spring Boot performance issues are fixable with the right strategy.
Back to topManaging Dependencies and Reducing Startup Time
This strategy is all about trimming the fat so your applications can startup and run efficiently.
Remove Unused Dependencies
Unnecessary dependencies significantly impact application startup times. Spring Boot's classpath scanning process searches through all available .class files and JAR archives for annotations like @Component, @Service, @Repository, and @Controller. The more dependencies you have, the longer this process takes.
Here are a few ways to identify unused dependencies:
- Maven: Run mvn dependency:analyze in your project's root directory. This command identifies unused declared dependencies, though it only detects compile-time issues, not runtime dependencies.
- Gradle: Execute gradle dependencies to view your dependency tree and manually identify candidates for removal.
- IDE Features: Modern IDEs like IntelliJ IDEA highlight unused dependencies in build files and offer dependency analysis tools through Maven or Gradle tool windows.
Some unused dependencies are introduced as transitive dependencies. In these cases, explicitly add <exclusions> tags within the dependency declaration to remove them.
After removing dependencies, rebuild and test your application thoroughly to ensure everything functions as expected.
Video Clip
Navigating Dependency Conflicts in Spring
Disable Unnecessary Auto-Configurations
Spring Boot's auto-configuration is convenient but can slow down startup when you're using only a fraction of the configured features. If you've added @EnableAutoConfiguration or @SpringBootApplication annotations, consider disabling specific auto-configuration classes.
Two approaches to disable auto-configurations:
Annotation-based exclusion:
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
Property-based exclusion in application.properties:
spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
Enable Lazy Initialization of Beans
By default, Spring eagerly initializes all singleton beans and their dependencies during ApplicationContext startup. This approach increases startup times, especially in larger applications.
Lazy initialization delays bean creation until they're actually needed, reducing initial startup overhead.
Here's how to do it:
- Application-wide: Set spring.main.lazy-initialization=true in your
application.propertiesfile - Bean-level: Use @Lazy on @Bean methods within @Configuration classes
- Component-level: Apply @Lazy to @Component or @Service classes
- Injection point: Add @Lazy to constructor parameters or fields where dependencies are injected
Use Spring Context Indexer
Spring Context Indexer generates a static list of component candidates at compilation time, eliminating runtime classpath scanning. This optimization creates a META-INF/spring.components file included in your JAR, allowing Spring to read the index directly.
Add the spring-context-indexer dependency to each module containing components targeted by component scan directives. This simple addition can dramatically reduce startup times in applications with extensive component scanning.
Code With JRebel
JRebel eliminates application redeployment and restart cycles during development. By instantly reflecting code changes without rebuilding or redeploying, JRebel saves significant development time and helps maintain focus without disrupting your workflow.
Back to topJVM Tuning and Memory Management Strategies
JVM performance directly impacts Spring Boot application responsiveness and throughput. Memory allocation, garbage collection, thread execution, and Just-In-Time (JIT) compilation all play critical roles in application performance.
Optimize Heap Size Configuration
The best practice for heap sizing is to set initial (-Xms) and maximum (-Xmx) heap sizes to the same value. This prevents the JVM from wasting resources on heap resizing and eliminates pause times associated with heap expansion.
Containerized environments (Docker/Kubernetes): If your container limit is 1GB, set -Xms and -Xmx between 600-700MB (60-70% of total memory). This leaves space for off-heap memory and prevents Out Of Memory errors.
Dedicated servers: Allocate 50-75% of available memory to the heap, reserving space for the operating system and other services.
Choose the Right Garbage Collector
Use the garbage collector for your SpringBoot application that corresponds to your specific performance goals or workload. Here's a table comparing G1 Garbage Collector (G1GC) vs. Z Garbage Collector (ZGC):
| Feature | G1GC (-XX:+UseG1GC) | ZGC (-XX:+UseZGC) |
| Performance Profile | Balanced performance and latency | Ultra-low and consistent pause times |
| Pause Behavior | Predictable pause times | Extremely short, near-pause-less operation |
| Throughput | High | Lower throughput due to concurrent overhead |
| Heap Size Suitability | Ideal for medium to large heaps | Excellent for very large heaps |
| Stability/Maturity | Stable across all Java versions | Newer; optimized for modern JVM versions |
| Memory Requirements | Memory efficient in constrained environments | Requires 15–25% memory headroom for optimal performance |
Monitor and Analyze JVM Performance
Regular monitoring helps identify performance issues before they impact production. Use these tools for comprehensive JVM analysis:
GUI tools:
- JConsole and JVisualVM for monitoring heap usage, garbage collection activity, and thread behavior
Command-line tools:
- jps, jstat, jmap, jcmd, and jstack for detailed heap and GC statistics
GC logging:
Enable garbage collection logging for detailed insights into collector behavior, throughput, and pause times.
Optimizing Embedded Web Servers
Apache Tomcat is the default embedded server for Spring Boot web applications. Optimize Tomcat performance through these application.properties settings:
server.tomcat.max-threads: Limits maximum concurrent requestsserver.tomcat.min-spare-threads: Sets minimum idle threadsserver.tomcat.connection-timeout: Defines client wait time before timeoutserver.tomcat.accept-count: Limits incoming connection queue size when threads are busy
While Tomcat is the default choice, alternative servers may offer performance advantages for specific use cases. For instance, Jetty could be ideal for microservices and cloud-native applications with small memory footprints to speed up startup and better asynchronous support. Undertow provides excellent throughput, which is suitable for servlet-compatible applications with incredibly low memory footprint, and provides efficient WebSocket support.
Configure Connection Pooling
Spring Boot uses HikariCP by default for connection pooling. HikariCP is highly efficient with low latency and minimal overhead. Fine-tune pool size based on your application's needs using the spring.datasource.hikari.maximum-pool-size property in application.properties.
Support
Deepen Spring Boot Expertise on Your Team
OpenLogic offers 24/7/365 technical support for Spring Boot, backed by SLAs, so your developers can stay focused on what matters to your business.
Spring Boot Troubleshooting and Diagnostics
Now let's look at how to figure out what's wrong when something's not working as expected.
Use Spring Boot Actuator
Spring Boot Actuator provides production-ready operational information through HTTP or JMX endpoints. Add the spring-boot-starter-actuator dependency to expose critical endpoints:
- /actuator/health: Basic application health information
- /actuator/metrics: CPU usage, JVM statistics, thread counts, and HTTP request metrics
- /actuator/threaddump: Thread dump for identifying performance issues
Security reminder: Always secure these endpoints using Spring Security in production environments.
Implement Effective Profiling
Profiling tools identify performance bottlenecks and memory issues before they reach production. Here are a few examples:
- XRebel: Lightweight Java analysis tool providing real-time performance insights during development. Features include database I/O monitoring, distributed tracing for microservices, and user-friendly debugging with reversed stack traces.
- VisualVM: Open-source profiler included with JDK. Offers real-time memory leak detection, thread analysis, CPU monitoring, and heap dump capabilities.
- JProfiler and YourKit: Commercial profilers offering comprehensive insights into CPU, memory, and thread usage, helping pinpoint resource-heavy methods.
- Java Flight Recorder (JFR) and JDK Mission Control (JMC): Low-overhead production profiling toolchain. JFR collects runtime data while JMC visualizes it for analysis.
Follow Logging Best Practices
Spring Boot uses Common Logging internally with flexible underlying implementations. Code against the SLF4J façade (org.slf4j.Logger interface) with Logback as the implementation. This approach provides flexibility to switch implementations if needed — for example, migrating to Log4j2 for enhanced performance.
Production Logging Recommendations
- Set logging levels to INFO, WARN, or ERROR to avoid performance degradation
- Avoid logging sensitive data
- Use parameterized logging instead of string concatenation for better performance
- Implement asynchronous appenders (Logback's AsyncAppender or Log4j2's Async Loggers) for high-throughput applications
- Use Mapped Diagnostic Context (MDC) to add contextual information like requestID or sessionID
- Integrate centralized logging systems (Splunk, Grafana Loki) with appropriate alerting
Address Common Production Bottlenecks
The most frequent performance issues in production Spring Boot applications include:
- Slow database queries
- Untuned database connection pools
- Memory leaks
- Improper embedded server configuration
- Suboptimal JVM settings
Regular Spring Boot monitoring, profiling, and applying the tuning strategies outlined in this guide will help you identify and resolve these bottlenecks proactively.
Back to topFinal Thoughts
Optimizing Spring Boot performance requires a comprehensive approach encompassing dependency management, JVM tuning, server configuration, and proactive monitoring. By implementing these strategies systematically, you can significantly reduce startup times, improve runtime performance, and ensure your applications scale efficiently in production environments.
Start by auditing your dependencies and auto-configurations, then progressively optimize your JVM settings and embedded server configuration. Over time, these incremental optimizations will add up to into meaningful gains in stability, responsiveness, and cost efficiency. And if you are concerned about developer productivity, you can always tap OpenLogic for expert support and guidance.