Application Properties
Application Properties
Every non-trivial Spring Boot application needs to behave differently in different environments: a laptop developer database is not the production database, a test mail server is not the live SMTP relay, and debug-level logging is not appropriate in production. Spring Boot solves this through a unified, layered configuration system built around application.properties and its YAML sibling application.yml. This lesson covers how that system works, what you can configure, and the patterns experienced developers rely on every day.
Where Spring Boot Looks for Configuration
Spring Boot resolves configuration from multiple sources and merges them in a well-defined precedence order (higher number wins):
- Default property values coded inside auto-configurations
application.properties/application.ymlinside the packaged JAR (on the classpath root, i.e.src/main/resources/)- Profile-specific files:
application-{profile}.propertieson the classpath - Same files outside the JAR, in the working directory
- OS environment variables
- JVM system properties (
-Dserver.port=9090) - Command-line arguments (
--server.port=9090)
src/main/resources/application.properties, and ops can override any value at runtime without recompiling.
Properties vs YAML — Which to Choose
.properties files use flat key-value pairs:
.yml (YAML) files express the same information as a nested tree:
Both are equivalent. YAML is more readable for deeply nested structures and supports lists cleanly; .properties is simpler to grep and is familiar to most Java veterans. Spring Boot 3 supports both. Do not mix them in the same project — pick one and be consistent.
Commonly Used Spring Boot Properties
Spring Boot ships with thousands of configuration keys documented in its Common Application Properties reference. The ones you will touch most often are:
Server
DataSource and JPA
Logging
Spring MVC
Binding Properties to a Configuration Class
Scattering @Value("${my.key}") annotations throughout your codebase is fragile and hard to test. The idiomatic Spring Boot 3 approach is @ConfigurationProperties: you define a plain Java record or class, annotate it, and Spring binds the matching prefix from application.properties directly into the object — with type conversion, validation, and IDE autocompletion included.
Register it in your main application class (or any @Configuration class):
Inject it anywhere with a plain constructor parameter (Spring Boot auto-wires it as a bean):
@ConfigurationProperties on a record uses the canonical constructor, so every property is required unless annotated with @DefaultValue. The result is an immutable, null-safe configuration object you can inject and test without mocking any Spring context.
Profiles — Environment-Specific Configuration
Profiles let you maintain separate configuration sets for dev, test, and prod without touching a single line of Java. Create a profile-specific file:
application-dev.properties— developer settings (H2 in-memory DB, verbose logging)application-prod.properties— production settings (PostgreSQL, log level INFO, no SQL echo)
Activate a profile at runtime — no recompile required:
${DB_PASS} inside application-prod.properties tells Spring Boot to resolve the value from an OS environment variable named DB_PASS. Use this for all passwords, API keys, and tokens. Secrets in .properties files that are checked into Git are a serious security risk.
The @Value Annotation — When It Still Makes Sense
@Value is useful for injecting a single property into a bean when a full @ConfigurationProperties class would be overkill:
The :unknown suffix is the default value if the key is missing. Use @Value sparingly — it bypasses type safety and is harder to test. Prefer @ConfigurationProperties for any group of related settings.
Summary
Spring Boot's configuration system is layered: defaults in the JAR, overrides in profile-specific files, final overrides via environment variables and command-line arguments. You write shared settings in application.properties, environment-specific settings in application-{profile}.properties, and bind groups of related properties into type-safe @ConfigurationProperties records. Secrets never live in files — they come from the environment at runtime. Master this system and you will rarely need to change compiled code just to adjust application behaviour.