Walk through Spring Boot's documented property-source precedence order from lowest to highest priority. Where do config files, OS env vars, SPRING_APPLICATION_JSON, and command-line args sit?
answer
- defaults < @PropertySource < config files < random < env < system props < SAJ < CLI < tests
- env vars beat application.yml
- -D system props beat env vars
- SPRING_APPLICATION_JSON beats -D
- CLI args beat SAJ; tests beat all
basics
~20 sRoughly, from lowest to highest: framework defaults, then application.properties/yml config files, then OS environment variables, then Java system properties, then SPRING_APPLICATION_JSON, then command-line arguments, then test overrides. Higher sources override lower ones for the same key.
solid answer
~40 sFrom lowest to highest priority: (1) default properties set via SpringApplication.setDefaultProperties; (2) @PropertySource on @Configuration classes; (3) config data — application.properties/yml and profile variants; (4) RandomValuePropertySource (random.*); (5) OS environment variables; (6) Java system properties (System.getProperties, i.e. -D flags); (7) JNDI attributes; (8) ServletContext / ServletConfig init params; (9) SPRING_APPLICATION_JSON (inline JSON in an env var or system property); (10) command-line arguments (--key=value); (11) @SpringBootTest 'properties'; (12) @TestPropertySource; and, when devtools is active, ~/.config/spring-boot devtools settings on top. The key takeaways interviewers want: env vars beat the config files, system properties beat env vars, SPRING_APPLICATION_JSON beats system properties, command-line args beat all of those, and test annotations override everything at test time.
code
java · 21 lines// Demonstrating the climb in priority for the key server.port:
//
// application.yml server.port: 8080 (lowest here)
// OS env var SERVER_PORT=8081 (beats the file)
// JVM system property -Dserver.port=8082 (beats env var)
// SPRING_APPLICATION_JSON {"server":{"port":8083}} (beats -D)
// command-line arg --server.port=8084 (beats SAJ)
//
// Launched all at once:
// SERVER_PORT=8081 \
// SPRING_APPLICATION_JSON='{"server":{"port":8083}}' \
// java -Dserver.port=8082 -jar app.jar --server.port=8084
// Effective server.port == 8084 (command-line wins).
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.TestPropertySource;
// In tests, @TestPropertySource overrides even command-line args:
@SpringBootTest(properties = "server.port=9000")
@TestPropertySource(properties = "server.port=9999") // this one wins in-test
class PrecedenceTest { }go deeper
Knows CLI args and env vars beat the files; not expected to recite the full ordered list.
Should order the common runtime sources: files < env < system props < CLI.
Should reproduce the documented order including SPRING_APPLICATION_JSON and test-annotation overrides, and explain the surprising placements.
Uses the order to design a coherent per-environment override strategy and to reason about test determinism and bootstrap-time keys.
## Why an order exists Spring Boot's `Environment` holds many `PropertySource`s. For any key, the **first source in priority order that contains it wins**. The reference documentation fixes this order so behavior is predictable across apps. Below, sources are listed **low priority first**; each later item overrides earlier ones on conflicting keys. ## The documented order (low → high) 1. **Default properties** — supplied programmatically via `SpringApplication.setDefaultProperties(...)`. The absolute fallback. 2. **`@PropertySource` on `@Configuration` classes** — note these are added late (during context refresh), so they cannot influence early bootstrap keys; useful mostly for supplemental static properties. 3. **Config Data files** — `application.properties` / `application.yml` and their `application-{profile}.*` variants, from the default locations (classpath and filesystem). This is the tier most app config lives in. 4. **`RandomValuePropertySource`** — resolves `random.int`, `random.long`, `random.uuid`, etc. 5. **OS environment variables** — e.g. `SERVER_PORT`. Uses **relaxed binding**: `SPRING_DATASOURCE_URL` maps to `spring.datasource.url`. 6. **Java System properties** — `System.getProperties()`, set with JVM `-Dkey=value` flags. These override OS env vars. 7. **JNDI attributes** from `java:comp/env`. 8. **ServletContext init parameters**, then **ServletConfig init parameters** (traditional servlet-container config). 9. **`SPRING_APPLICATION_JSON`** — a blob of JSON provided in an environment variable (`SPRING_APPLICATION_JSON`) or system property (`spring.application.json`), parsed and flattened into properties. It overrides system properties and env vars. 10. **Command-line arguments** — `--key=value` after the jar, captured as a `CommandLinePropertySource`. Highest of the 'normal runtime' sources. 11. **`properties` attribute on tests** — e.g. `@SpringBootTest(properties = "server.port=0")` and slice-test annotations. 12. **`@TestPropertySource`** — overrides even the test `properties` attribute. 13. **Devtools global settings** in `$HOME/.config/spring-boot` — only when spring-boot-devtools is active; layered on top for local development. ## The exam-relevant relationships - **Env vars > config files.** A `SERVER_PORT` environment variable overrides `server.port` in application.yml. This is the crux of 12-factor / container config. - **System properties (-D) > env vars.** `-Dserver.port` beats a `SERVER_PORT` env var. - **SPRING_APPLICATION_JSON > system properties.** The JSON blob outranks -D flags. - **Command-line args > SPRING_APPLICATION_JSON.** `--server.port=...` beats everything except test overrides/devtools. - **Tests override everything** so a test can pin config deterministically. ## Common surprises - People assume `SPRING_APPLICATION_JSON` is low priority because it's an env var. It isn't — it's its own high-priority source, above plain OS env vars and above `-D` system properties. - People assume env vars and system properties are the same tier; system properties actually outrank env vars. - `@PropertySource` is *low* priority and added late, so it rarely 'wins' against the config-data files, and cannot supply bootstrap-time keys. - Devtools reordering only applies with devtools on the classpath (dev only) — never rely on it in production. ## Practical guidance Bake defaults into `application.yml`; override per environment with **environment variables** (they cleanly beat files and are the container-native mechanism); reserve **command-line args** for one-off launches/scripts; use **SPRING_APPLICATION_JSON** when a platform lets you inject one structured blob; use **`@TestPropertySource`** to make tests deterministic.
- Between a SERVER_PORT environment variable and a -Dserver.port system property, which wins?The system property wins. Java system properties (set with -D) sit above OS environment variables in the precedence order, so -Dserver.port overrides SERVER_PORT.
- Is SPRING_APPLICATION_JSON just another environment variable, precedence-wise?No. Although it's usually delivered via an env var, Spring Boot treats it as its own dedicated high-priority source that ranks above plain OS env vars and above -D system properties, and just below command-line arguments.
saying these in an interview costs you the question
- Placing OS env vars above system properties
- Treating SPRING_APPLICATION_JSON as a low-priority ordinary env var
- Claiming application.properties outranks env vars/CLI args
- Believing @PropertySource can override config-data files or set bootstrap keys