Spring Boot Performance: Beyond the Defaults
Default configurations are starting points, not destinations. How we cut our API response times by 60%.
Spring Boot's "convention over configuration" philosophy is brilliant for getting started. But in production, those conventions can cost you.
Here's how we systematically improved our payroll API from ~800ms p95 to ~320ms p95.
1. Connection Pool Tuning
The default HikariCP settings are conservative. For our workload:
spring:
datasource:
hikari:
maximum-pool-size: 20
minimum-idle: 5
connection-timeout: 3000
idle-timeout: 600000We also added connection pool metrics to Datadog. Watching pool utilization over time revealed that our original pool size of 10 was causing thread contention during payroll calculation windows.
2. JPA N+1 Query Elimination
The silent killer. We used Spring Data JPA's @EntityGraph annotations and switched critical queries to projections:
@EntityGraph(attributePaths = {"employee", "deductions"})
List<PayrollRecord> findByPeriod(String period);This alone cut our main calculation endpoint from 1.2s to 400ms.
3. Redis Caching Strategy
Not everything needs to hit the database. We implemented a tiered caching strategy:
4. Virtual Threads (Java 21)
Migrating to virtual threads was the final piece. Our I/O-heavy workload benefited massively:
The key takeaway: measure first, optimize second. Every change above was driven by profiling data, not intuition.