How do application.properties/application.yml and Spring profiles work together?
Quick Answer
application.properties/application.yml hold externalized configuration (data source URLs, server port, feature flags) that Spring Boot's Environment abstraction exposes to the application, keeping config out of code. Profiles let you maintain environment-specific variants of that configuration (application-dev.yml, application-prod.yml) that layer on top of the base file, activated via the spring.profiles.active property — letting the same deployable artifact behave differently in different environments without code changes.
Detailed Answer
application.properties (or the YAML equivalent, application.yml) is Spring Boot's default place for externalized configuration — values that shouldn't be hardcoded (database URLs, server port, feature flags, third-party API keys) live here instead of in Java code, and are exposed to the application through Spring's Environment abstraction (readable via @Value("${my.property}") or bound to a @ConfigurationProperties class).
server:
port: 8080
spring:
datasource:
url: jdbc:postgresql://localhost:5432/mydb
Profiles let you maintain multiple, environment-specific variants of this configuration without duplicating everything:
application.yml # common, base configuration
application-dev.yml # overrides/additions specific to the "dev" profile
application-prod.yml # overrides/additions specific to the "prod" profile
Only the properties that actually differ need to appear in a profile-specific file — anything not overridden there falls back to the base application.yml.
Activating a profile:
java -jar app.jar --spring.profiles.active=prod
# or via an environment variable: SPRING_PROFILES_ACTIVE=prod
Profiles also gate which beans are active, via @Profile:
@Configuration
@Profile("dev")
class DevOnlyConfig {
@Bean
DataSource embeddedDataSource() { return new EmbeddedDatabaseBuilder().build(); } // only wired up in "dev"
}
Precedence, briefly: Spring Boot resolves configuration from many sources (command-line args, environment variables, profile-specific files, the base file, defaults) using a well-defined precedence order, where more specific/explicit sources (command-line args, active profile files) override more general ones (the base application.yml) — this layered override model is exactly what lets the same built artifact run correctly across local, staging, and production environments purely by changing which profile is active, with no rebuild required.