Spring Boot Cheatsheet

Configuration

Use this Spring Boot reference while you build software engineering projects, review code for technical interview prep, or polish examples for a software engineer resume.

application.properties vs application.yml

Both formats are equivalent. Properties files are simpler; YAML is more readable for nested config.

# application.properties
server.port=8080
spring.datasource.url=jdbc:postgresql://localhost:5432/mydb
spring.datasource.username=user
spring.datasource.password=secret
# application.yml
server:
  port: 8080
spring:
  datasource:
    url: jdbc:postgresql://localhost:5432/mydb
    username: user
    password: secret

Spring Boot loads both; properties take precedence over YAML when both exist. Use one format per project.

Property Sources and Precedence (highest → lowest)

  1. Command-line arguments (--server.port=9090)
  2. SPRING_APPLICATION_JSON env var
  3. Servlet / init parameters
  4. OS environment variables
  5. application-{profile}.properties (profile-specific, outside jar)
  6. application.properties (outside jar)
  7. application-{profile}.properties (inside jar)
  8. application.properties (inside jar)
  9. @PropertySource annotations
  10. Default properties (SpringApplication.setDefaultProperties)

Profiles

# application-dev.properties
spring.datasource.url=jdbc:h2:mem:testdb
spring.jpa.hibernate.ddl-auto=create-drop
logging.level.com.example=DEBUG

# application-prod.properties
spring.datasource.url=${DATABASE_URL}
spring.jpa.hibernate.ddl-auto=validate
logging.level.root=WARN
# Activate at runtime
java -jar app.jar --spring.profiles.active=prod

# Or via env var
SPRING_PROFILES_ACTIVE=prod java -jar app.jar
// Activate in code
@SpringBootApplication
public class App {
    public static void main(String[] args) {
        SpringApplication app = new SpringApplication(App.class);
        app.setAdditionalProfiles("dev");
        app.run(args);
    }
}

// Conditional beans on profile
@Service
@Profile("dev")
public class MockEmailService implements EmailService { ... }

@Service
@Profile("!dev")   // all profiles except dev
public class RealEmailService implements EmailService { ... }

@Service
@Profile({"prod", "staging"})
public class ProductionEmailService implements EmailService { ... }

@ConfigurationProperties — Typed Config

Preferred over @Value for groups of related properties.

# application.properties
app.mail.host=smtp.gmail.com
app.mail.port=587
app.mail.username=noreply@example.com
app.mail.password=secret
app.mail.from=Hack University <noreply@example.com>
app.mail.retry-count=3
@ConfigurationProperties(prefix = "app.mail")
@Validated   // triggers Bean Validation on the properties
public record MailProperties(
    @NotBlank String host,
    @Min(1) @Max(65535) int port,
    @NotBlank String username,
    @NotBlank String password,
    @NotBlank String from,
    @Min(0) int retryCount
) {}
// Register — pick ONE of:
@SpringBootApplication
@ConfigurationPropertiesScan  // scans for @ConfigurationProperties

// Or per-class:
@EnableConfigurationProperties(MailProperties.class)
// Inject like any bean
@Service
@RequiredArgsConstructor
public class MailService {
    private final MailProperties mail;
}

@Value — Single Property Injection

@Component
public class AppInfo {
    @Value("${app.name}")
    private String appName;

    @Value("${app.max-connections:10}")   // default value after ':'
    private int maxConnections;

    @Value("${app.allowed-origins}")      // injects List<String> from CSV
    private List<String> allowedOrigins;

    @Value("#{T(java.lang.Math).PI}")     // SpEL expression
    private double pi;

    @Value("${app.secret:#{null}}")       // null default
    private String secret;
}

Avoid @Value for more than 2-3 related properties in the same class; prefer @ConfigurationProperties instead.

Environment and PropertySources

@Component
public class EnvInspector {

    private final Environment env;

    public EnvInspector(Environment env) {
        this.env = env;
    }

    public String getProperty(String key) {
        return env.getProperty(key, "default");
    }

    public boolean isDevProfile() {
        return env.acceptsProfiles(Profiles.of("dev"));
    }
}

Custom @PropertySource

@Configuration
@PropertySource("classpath:custom.properties")
@PropertySource(value = "file:/etc/myapp/secrets.properties", ignoreResourceNotFound = true)
public class ExtraConfig {}

Externalized Secrets — Best Practices

# Reference env vars in properties
spring.datasource.password=${DB_PASSWORD}
jwt.secret=${JWT_SECRET}
stripe.api-key=${STRIPE_SECRET_KEY}
// Or use Spring Cloud Vault / AWS Parameter Store / Kubernetes Secrets
// spring-cloud-starter-vault-config
spring.cloud.vault.uri=http://vault:8200
spring.cloud.vault.authentication=TOKEN
spring.cloud.vault.token=${VAULT_TOKEN}

@Configuration Classes

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/api/**")
                .allowedOrigins("https://myapp.com")
                .allowedMethods("GET", "POST", "PUT", "DELETE");
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoggingInterceptor())
                .addPathPatterns("/api/**")
                .excludePathPatterns("/api/health");
    }

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        converters.add(new MappingJackson2HttpMessageConverter());
    }
}

Logging Configuration

# Root level
logging.level.root=INFO

# Package-level
logging.level.com.example=DEBUG
logging.level.org.hibernate.SQL=DEBUG
logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE

# File output
logging.file.name=logs/app.log
logging.file.max-size=10MB
logging.file.max-history=30

# Pattern
logging.pattern.console=%d{HH:mm:ss} %-5level %logger{36} - %msg%n
// In code (SLF4J — included via spring-boot-starter)
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Service
public class OrderService {
    private static final Logger log = LoggerFactory.getLogger(OrderService.class);
    // Or with Lombok:
    // @Slf4j on the class
    
    public void process(Order order) {
        log.debug("Processing order {}", order.getId());
        log.info("Order {} processed", order.getId());
        log.warn("Order {} has unusual amount: {}", order.getId(), order.getTotal());
        log.error("Failed to process order {}", order.getId(), exception);
    }
}

Common Server Properties

server.port=8080
server.servlet.context-path=/api          # global URL prefix
server.error.include-message=always       # include message in error response
server.error.include-stacktrace=never     # never expose stack in prod
server.compression.enabled=true
server.compression.mime-types=application/json,application/xml,text/html
server.compression.min-response-size=1024

# SSL / TLS
server.ssl.key-store=classpath:keystore.p12
server.ssl.key-store-password=${KEYSTORE_PASS}
server.ssl.key-store-type=PKCS12
server.port=443

Jackson / Serialization Properties

spring.jackson.serialization.write-dates-as-timestamps=false
spring.jackson.default-property-inclusion=non_null
spring.jackson.deserialization.fail-on-unknown-properties=false
spring.jackson.time-zone=UTC
spring.jackson.date-format=yyyy-MM-dd'T'HH:mm:ss'Z'

Common Pitfalls

  • @ConfigurationProperties not found — add @ConfigurationPropertiesScan or @EnableConfigurationProperties; also add spring-boot-configuration-processor to annotation processors for IDE autocomplete.
  • Env var name mappingAPP_MAIL_HOST maps to app.mail.host (relaxed binding with underscores and uppercase).
  • @Value with @Configuration — if a @Configuration class uses @Value AND declares @Bean methods, property resolution happens before bean creation; use constructor injection or @ConfigurationProperties to avoid ordering issues.
  • Profile-specific YAML in one file — use --- document separators with spring.config.activate.on-profile (Spring Boot 2.4+).
  • logging.level at runtime — change via Actuator /actuator/loggers/{name} without restart.