Avoid Hidden SpringBoot Pitfalls: Optimize Default Settings for Production

This article examines common default configuration issues in SpringBoot—such as Tomcat connection limits, HikariCP pool size, JPA lazy loading, Jackson timezone handling, logging, caching, file upload limits, async execution, and transaction timeouts—and provides practical adjustments to improve performance and reliability in production environments.

Architect
Architect
Architect
Avoid Hidden SpringBoot Pitfalls: Optimize Default Settings for Production

Introduction

When SpringBoot first emerged, its "convention over configuration" approach attracted many developers, promising "out‑of‑the‑box" simplicity. However, many default settings hide assumptions that can cause serious problems in real‑world deployments.

Tomcat Connection Pool

SpringBoot uses Tomcat as the default web container, but the default maximum connections and threads are only 200. In high‑concurrency scenarios this quickly becomes a bottleneck.

server:
  tomcat:
    max-connections: 10000  # maximum connections
    threads:
      max: 800               # maximum worker threads
      min-spare: 100          # minimum idle threads
    accept-count: 100       # queue length
    connection-timeout: 20000

The default timeout is unlimited, causing connections to linger and exhaust resources.

Database Connection Pool

SpringBoot defaults to HikariCP with a maximum pool size of 10, which is insufficient for most production workloads.

spring:
  datasource:
    hikari:
      maximum-pool-size: 50
      minimum-idle: 10
      connection-timeout: 30000
      idle-timeout: 600000
      max-lifetime: 1800000
      leak-detection-threshold: 60000

Pay special attention to leak-detection-threshold; it is disabled by default, so connection leaks may go unnoticed.

JPA Lazy Loading

SpringBoot enables lazy loading by default, which can lead to N+1 query problems.

@Entity
public class User {
    @Id
    private Long id;
    @OneToMany(fetch = FetchType.LAZY)
    private List<Order> orders;
}

When fetching a list of users, each access to orders triggers an additional query. Solutions include using @EntityGraph, JOIN FETCH, or adjusting fetch strategies.

Jackson Timezone Serialization

Jackson uses the system timezone by default, causing inconsistent timestamps across distributed deployments.

spring:
  jackson:
    time-zone: GMT+8
    date-format: yyyy-MM-dd HH:mm:ss
    serialization:
      write-dates-as-timestamps: false

Explicitly setting the timezone and disabling timestamp serialization avoids this issue.

Log Configuration

The default Logback configuration lacks file rotation and size limits, leading to ever‑growing log files.

logging:
  file:
    name: app.log
  logback:
    rollingpolicy:
      max-file-size: 100MB
      max-history: 30
      total-size-cap: 3GB

Adjust log levels to reduce noise in production.

Cache Configuration

The default @Cacheable implementation uses a plain ConcurrentHashMap without expiration or size limits, which can cause memory overflow under load. Switching to Caffeine provides better eviction policies.

spring:
  cache:
    type: caffeine
    caffeine:
      spec: maximumSize=10000,expireAfterWrite=600s

Monitoring Endpoints

SpringBoot Actuator exposes many endpoints by default, which may leak sensitive information. Expose only necessary endpoints and secure them.

management:
  endpoints:
    web:
      exposure:
        include: health,info,metrics
  endpoint:
    health:
      show-details: when-authorized

File Upload Limits

The default upload limits (1 MB per file, 10 MB total) are often too low for real applications.

spring:
  servlet:
    multipart:
      max-file-size: 100MB
      max-request-size: 100MB
      file-size-threshold: 2KB
      location: /tmp
      resolve-lazily: false

Adjust file-size-threshold appropriately to balance memory and disk usage.

Async Thread Pool

Using @Async without a proper thread pool defaults to SimpleAsyncTaskExecutor, which creates a new thread for each task and can exhaust resources.

spring:
  task:
    execution:
      pool:
        core-size: 8
        max-size: 16
        queue-capacity: 100
        keep-alive: 60s
        thread-name-prefix: async-task-
    scheduling:
      pool:
        size: 4
        thread-name-prefix: scheduling-

Configure core and max sizes based on CPU‑bound or I/O‑bound workloads.

Static Resource Caching

SpringBoot does not set HTTP cache headers for static assets by default, causing browsers to re‑download unchanged files.

spring:
  web:
    resources:
      cache:
        cachecontrol:
          max-age: 365d
          cache-public: true
        strategy:
          content:
            enabled: true
            paths: /**
            cache: true
      static-locations: classpath:/static/

Enabling content‑based versioning (e.g., style-abc123.css) ensures browsers cache unchanged resources.

Database Transaction Timeout

Without a timeout, long‑running transactions hold database locks, leading to contention.

@Transactional(timeout = 30, rollbackFor = Exception.class)
public void batchProcess(List<Data> dataList) {
    int batchSize = 100;
    for (int i = 0; i < dataList.size(); i += batchSize) {
        List<Data> batch = dataList.subList(i, Math.min(i + batchSize, dataList.size()));
        processBatch(batch);
    }
}

Splitting large jobs into smaller transactions releases locks sooner and improves concurrency.

Conclusion

SpringBoot’s conventions save development effort but can hide assumptions that don’t fit every production scenario. Proactively reviewing and tuning defaults—connection pools, caching, logging, async execution, and transaction settings—helps avoid costly incidents and ensures a robust, performant system.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Javaperformance tuningSpringBootdefault configuration
Architect
Written by

Architect

Professional architect sharing high‑quality architecture insights. Topics include high‑availability, high‑performance, high‑stability architectures, big data, machine learning, Java, system and distributed architecture, AI, and practical large‑scale architecture case studies. Open to ideas‑driven architects who enjoy sharing and learning.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.