How do OS environment variables map to Spring property names (relaxed binding), and what is SPRING_APPLICATION_JSON used for?
answer
- Dots -> underscores, UPPERCASE
- Double underscore __ = hyphen
- index: _0_ for list[0]
- SPRING_APPLICATION_JSON = one blob, flattened
- SAJ high priority, above env & -D
basics
~20 sBecause shells only allow uppercase letters, digits, and underscores, Spring Boot uses 'relaxed binding': an env var like SPRING_DATASOURCE_URL maps to spring.datasource.url (dots become underscores, uppercased). SPRING_APPLICATION_JSON lets you inject many properties at once as a single JSON string.
solid answer
~40 sOS environment variables can't contain dots or hyphens, so Spring Boot's relaxed binding canonicalizes names: uppercase with underscores maps to the dotted lowercase property. `SPRING_DATASOURCE_URL` binds `spring.datasource.url`; a double underscore `__` represents a hyphen, and `_INDEX_` style suffixes handle list elements (e.g. `MY_LIST_0_`). This is the standard way to configure containerized apps, and env vars outrank the application.properties/yml files. `SPRING_APPLICATION_JSON` (or the `spring.application.json` system property) is a single environment variable holding a JSON document that Spring parses and flattens into properties — handy when a platform gives you one variable but you need to set a whole tree of config. It ranks high in precedence: above plain env vars and system properties, just below command-line arguments. Use env vars for individual overrides and SPRING_APPLICATION_JSON when you want to inject a structured block at once.
code
kotlin · 23 lines// application.yml expects:
// spring.datasource.url
// server.tomcat.max-connections
// myapp.servers[0].host
//
// Set them purely from environment variables (relaxed binding):
// export SPRING_DATASOURCE_URL=jdbc:postgresql://db:5432/app
// export SERVER_TOMCAT_MAX__CONNECTIONS=200 # __ = hyphen
// export MYAPP_SERVERS_0_HOST=node-a # _0_ = list index 0
//
// Or inject a whole tree at once via SPRING_APPLICATION_JSON:
// export SPRING_APPLICATION_JSON='{"server":{"port":9000},"myapp":{"name":"orders"}}'
// java -jar app.jar # server.port=9000, myapp.name=orders
import org.springframework.boot.context.properties.ConfigurationProperties
@ConfigurationProperties(prefix = "myapp")
data class MyAppProps(
val name: String = "",
val servers: List<Server> = emptyList(),
) {
data class Server(val host: String = "")
}go deeper
Knows env vars can override config; may not know the exact relaxed-binding mapping.
Should state the dot->underscore/uppercase mapping, the __ = hyphen rule, and what SPRING_APPLICATION_JSON does.
Should place both sources in the precedence order and handle list-index binding and shell escaping.
Chooses between per-var overrides vs a single JSON blob per platform constraints, and pairs env config with secret management.
## The problem relaxed binding solves Property names are conventionally dotted, lowercase, hyphenated: `spring.datasource.url`, `server.tomcat.max-connections`. But OS environment variables in most shells may only use **uppercase letters, digits, and underscores** — no dots, no hyphens, no lowercase reliably. Spring Boot bridges this with **relaxed binding** (implemented around `@ConfigurationProperties` binding and `SystemEnvironmentPropertySource`). ## The canonical mapping rules To set a property from an environment variable: - **Uppercase the property name.** - **Replace dots (`.`) with underscores (`_`).** - **Remove hyphens or replace a hyphen with `_`** — more precisely, a **double underscore (`__`)** in the env var is treated as an escaped hyphen. - **List/array indices**: use an underscore-bounded numeric index. `MY_APP_SERVERS_0_HOST` maps to `my.app.servers[0].host`. Examples: | Environment variable | Property | |---|---| | `SPRING_DATASOURCE_URL` | `spring.datasource.url` | | `SERVER_PORT` | `server.port` | | `SERVER_TOMCAT_MAX__CONNECTIONS` | `server.tomcat.max-connections` | | `MYAPP_SERVERS_0_HOST` | `myapp.servers[0].host` | Relaxed binding is **one-directional at read time**: it works cleanly for `@ConfigurationProperties`-bound beans and for env vars; a few edge cases (like `@Value` with an exact key) are stricter, so prefer `@ConfigurationProperties` when relying on env-var binding. ## Precedence reminder OS environment variables sit **above** the config-data files (application.properties/yml) but **below** Java system properties and SPRING_APPLICATION_JSON. So `SERVER_PORT` overrides the yml but is itself overridden by `-Dserver.port` and by `--server.port`. ## SPRING_APPLICATION_JSON Sometimes a platform only lets you set **one** environment variable but you need to inject a whole tree of configuration. `SPRING_APPLICATION_JSON` accepts a JSON document as its value; Spring Boot parses and **flattens** it into individual properties. Provide it as: - The `SPRING_APPLICATION_JSON` **environment variable**, or - The `spring.application.json` **system property** (`-Dspring.application.json=...`), or - A JNDI variable `java:comp/env/spring.application.json`. Example: `SPRING_APPLICATION_JSON='{"server":{"port":9000},"myapp":{"name":"orders"}}'` sets `server.port=9000` and `myapp.name=orders`. It is a **high-priority** source — above OS env vars and system properties, just below command-line arguments — so it overrides the files and plain env vars. ## Gotchas - **Quoting/escaping**: the JSON must be valid and correctly quoted for your shell; malformed JSON causes startup failure. - **Precedence surprise**: engineers assume the JSON is 'just an env var' and rank it low — it's actually near the top. - **Relaxed binding only accepts the canonical env-var form**; arbitrary casing like `Spring_Datasource_Url` won't reliably bind. - **List indices** must use the numeric-underscore form; forgetting the trailing structure yields unbound values. - **Secrets**: env vars and SPRING_APPLICATION_JSON are visible in the process environment — combine with a secrets manager for sensitive values, and remember env vars override files, which is exactly why they're the container override mechanism. ## When to use which Use **individual env vars** for a handful of per-environment overrides (the 12-factor default). Use **SPRING_APPLICATION_JSON** when you must inject a structured block through a single variable (some PaaS/CI systems). Use **command-line args** for ad-hoc launches. Keep static defaults in the yml.
- Given the property server.tomcat.max-connections, what environment variable name sets it?SERVER_TOMCAT_MAX__CONNECTIONS — dots become single underscores, the whole name is uppercased, and the hyphen in 'max-connections' is represented by a double underscore.
- Does SPRING_APPLICATION_JSON override a value set in an ordinary environment variable?Yes. SPRING_APPLICATION_JSON is a higher-priority source than plain OS environment variables (and Java system properties), so a key present in both takes its value from the JSON blob.
saying these in an interview costs you the question
- Claiming env vars can contain dots so SPRING.DATASOURCE.URL works
- Thinking SPRING_APPLICATION_JSON is low priority because it's an env var
- Using a single underscore to represent a hyphen (it's a double underscore)
- Assuming relaxed binding accepts arbitrary mixed-case env var names