Where performance usually leaks
Spring Boot bottlenecks are rarely “framework magic”. More often: blocking calls on a reactive stack, oversized heaps from caches, slow SQL without indexes, poorly sized connection pools, and missing timeouts on outbound HTTP clients.
Pools and timeouts
For HikariCP, size the pool from load tests and metrics — not folklore alone. Always set:
connectionTimeout,maxLifetime;- statement/query timeouts at the database layer;
- RestClient/WebClient connect + read timeouts.
spring.datasource.hikari.maximum-pool-size=20
spring.datasource.hikari.connection-timeout=3000
Caching
Caffeine for hot local reference data; Redis when replicas must share cache. Design TTL and invalidation up front. For read-heavy APIs, a service-level cache often beats micro-optimizing JSON serialization.
JVM in containers
On JDK 21 use container-aware flags (MaxRAMPercentage) and watch GC (G1 default; ZGC for low-latency cases). Virtual threads help high-concurrency blocking I/O on Spring MVC, but they will not fix missing database indexes.
Profile before you optimize
Measure first: Micrometer timers, p95/p99 latency, pool saturation, GC logs. Async Profiler / JFR show hot methods. Load tests (k6, Gatling) on staging with production-like data prevent release surprises.
Startup and warmup
Startup time matters for Kubernetes scale-out. Spring AOT, CDS/AppCDS, and trimming auto-configuration reduce cold start — topics frequently covered by the Spring team and platform engineers. GraalVM native helps scale-to-zero with known reflection/build trade-offs.
Takeaway
Spring Boot performance work is a measurement discipline: pools, timeouts, cache, SQL, JVM-in-container, and profiling. Start from SLOs and graphs — optimize only where the data points.
