Spring Boot Cheatsheet
Configuration
Use this Spring Boot reference while you build software engineering projects, review code, or refresh the syntax you reach for most.
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)
- Command-line arguments (
--server.port=9090) SPRING_APPLICATION_JSONenv var- Servlet / init parameters
- OS environment variables
application-{profile}.properties(profile-specific, outside jar)application.properties(outside jar)application-{profile}.properties(inside jar)application.properties(inside jar)@PropertySourceannotations- 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
@Valuefor more than 2-3 related properties in the same class; prefer@ConfigurationPropertiesinstead.
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
@ConfigurationPropertiesnot found — add@ConfigurationPropertiesScanor@EnableConfigurationProperties; also addspring-boot-configuration-processorto annotation processors for IDE autocomplete.- Env var name mapping —
APP_MAIL_HOSTmaps toapp.mail.host(relaxed binding with underscores and uppercase). @Valuewith@Configuration— if a@Configurationclass uses@ValueAND declares@Beanmethods, property resolution happens before bean creation; use constructor injection or@ConfigurationPropertiesto avoid ordering issues.- Profile-specific YAML in one file — use
---document separators withspring.config.activate.on-profile(Spring Boot 2.4+). logging.levelat runtime — change via Actuator/actuator/loggers/{name}without restart.