Foundation · Configure

Properties vs YAML

Externalize configuration into .properties or YAML and control which source wins when locations, environment variables, and command-line arguments overlap.

Primary source: Spring Boot 3.5 Reference: Externalized Configuration

15 min

Lesson 1 of 4

1d streak

The Architectural Question

Baking URLs, ports, and credentials into compiled code forces a rebuild per environment and walks secrets straight into version control.

What this guide proves

  • application.properties
  • application.yml
  • Environment Variables

Spring Boot Externalized Configuration Precedence

Externalized configuration allows the same compiled Spring Boot JAR to run unmodified across development workstations, CI test pipelines, staging clusters, and production data centers. Spring Boot builds a unified PropertySources hierarchy from over 15 distinct sources, evaluating them in a strict top-down precedence order where higher-priority sources override lower ones.

  1. 011. Command-line arguments (--server.port=9090 has the highest standard priority)
  2. 022. Java System properties (-Dserver.port=9090) passed to the JVM
  3. 033. OS Environment variables (SERVER_PORT=9090) standard for containers and Kubernetes
  4. 044. Kubernetes ConfigTree files (spring.config.import=configtree:/etc/config/)
  5. 055. Profile-specific application-{profile}.yml outside the packaged JAR
  6. 066. Profile-specific application-{profile}.yml inside the packaged JAR
  7. 077. Application default application.yml outside the packaged JAR
  8. 088. Application default application.yml inside the packaged JAR
  9. 099. Default properties defined on @PropertySource or SpringApplication.setDefaultProperties()

The Fail-Safe Rule

External configuration (outside the JAR or supplied via environment variables) always trumps packaged configuration (inside src/main/resources). This guarantees that ops teams can patch network ports, database hosts, and credentials without asking developers to recompile the application artifact.

Active Recall Checkpoint

If server.port=8080 is in application.yml inside the JAR, but SERVER_PORT=8090 is set in the OS environment, what port will Tomcat bind to at startup?

Hint: Review the precedence order between OS Environment variables and packaged application.yml.

Show answer & explanation

Port 8090. OS environment variables have significantly higher precedence than packaged YAML configuration files, allowing container platforms like Docker and Kubernetes to override port bindings effortlessly.

Properties vs YAML: Structure, Syntax & Subtle Pitfalls

Spring Boot natively supports both flat .properties files and hierarchical .yml (or .yaml) files. While both feed the identical Environment abstraction, their syntax rules and capabilities differ dramatically.

Architectural Boundary · Do Not Confuse

Concept A

application.properties: Flat key-value format. No native list hierarchy; keys repeat prefixes (app.mail.hosts[0]=...). Supported by @PropertySource.

Concept B

application.yml: Human-readable indentation hierarchy. Native lists and multi-document blocks (---). Not supported by standard @PropertySource.

YAML reduces prefix repetition and enables multi-document profile separation, but strict whitespace indentation and implicit type coercion can introduce silent configuration bugs.

application.yml
server:
  port: 8080
  shutdown: graceful

app:
  security:
    cors:
      allowed-origins:
        - "https://app.example.com"
        - "https://admin.example.com"
    feature-flags:
      enable-beta-checkout: false # Note: Avoid raw 'no' or 'off' which YAML parsers might coerce

The YAML Type Coercion Trap

Standard YAML 1.1 coerces unquoted values like "yes", "no", "on", "off", "true", and "false" into booleans. If a country code is set as country: NO (Norway), a naive parser treats it as country: false. Always quote string values in YAML when there is any ambiguity.

Active Recall Checkpoint

Can you use @PropertySource("classpath:custom.yml") on a @Configuration class to load custom YAML configuration?

Hint: Check Spring Framework core support for PropertySource vs Spring Boot configuration.

Show answer & explanation

No, not without registering a custom PropertySourceFactory backed by YamlPropertiesFactoryBean. Spring Framework's standard @PropertySource only parses standard Java .properties and XML files. Spring Boot recommends using spring.config.import instead.

Relaxed Binding & OS Environment Variable Mapping

Spring Boot provides relaxed binding: property names can be written in kebab-case, camelCase, snake_case, or uppercase screaming snake, and Boot maps them to the same destination. However, operating system environment variables have strict naming constraints (POSIX shells allow only alphanumeric characters and underscores).

Target Property (Canonical)Environment Variable FormatConversion Rule
server.portSERVER_PORTDot (.) converts to Underscore (_)
app.payment-service.api-keyAPP_PAYMENTSERVICE_APIKEY or APP_PAYMENT_SERVICE_API_KEYHyphens (-) are removed or converted to underscores
app.hosts[0]APP_HOSTS_0_Array index brackets [n] convert to _n_
app.endpoints[api.v1].timeoutAPP_ENDPOINTS_APIV1_TIMEOUTMap keys in dots are converted and flattened

The Spring Boot team strongly recommends writing all property keys in canonical kebab-case (e.g. app.payment-service.timeout-ms) inside application.yml and using uppercase screaming snake in environment variables (APP_PAYMENTSERVICE_TIMEOUTMS).

Active Recall Checkpoint

How would you override the property spring.datasource.hikari.maximum-pool-size=20 using an environment variable in a Docker container?

Hint: Convert dots and hyphens according to POSIX environment variable rules.

Show answer & explanation

Set SPRING_DATASOURCE_HIKARI_MAXIMUM_POOL_SIZE=20 (or SPRING_DATASOURCE_HIKARI_MAXIMUMPOOLSIZE=20). Both are resolved by Spring Boot's relaxed binding engine.

Deliberate Failure Lab: Hidden Property Shadowing & List Overriding

A frequent operational incident occurs when an engineer attempts to override a list property via environment variables. By default, environment variables do not append to existing lists; they replace entries by index or fail to match if array indexing syntax is not honored.

application.yml
app:
  admin-emails:
    - "alice@example.com"
    - "bob@example.com"
broken-run.sh
# Fails to replace the entire list as expected:
export APP_ADMIN_EMAILS="charlie@example.com"
# Result: Charlie does not append; depending on binder, it may crash or only bind to index 0 leaving index 1 intact!

How to Correctly Override Lists from Environment

To override a specific list element, specify the index explicitly: APP_ADMINEMAILS_0_="charlie@example.com". Alternatively, use comma-delimited strings (APP_ADMIN_EMAILS="charlie@example.com,david@example.com") bound to a List<String> or Set<String> in @ConfigurationProperties.

Active Recall Checkpoint

Why should you prefer comma-delimited string properties over YAML multi-line arrays when frequent environment overrides are required?

Hint: Consider how container environment variables represent lists vs scalar strings.

Show answer & explanation

A single environment variable like APP_ALLOWED_ORIGINS="https://a.com,https://b.com" can completely replace the list without needing indexed environment variables (_0_, _1_), making orchestration manifests in Kubernetes and Docker Compose simpler and less prone to partial shadowing.

Runtime Architecture & Flow

Resolution model

A practical override ladder

  1. 1

    Packaged application defaults

  2. 2

    Profile-specific configuration

  3. 3

    External application configuration

  4. 4

    Environment and system properties

  5. 5

    Command-line arguments

Higher layers represent a simplified operational view of stronger overrides. Spring Boot has additional property sources, so use the Environment or Actuator env endpoint when diagnosing an exact value.

Synthesis & Production Verification

Production Acceptance Criteria

  • Write equivalent configuration in .properties and YAML
  • Override server.port with SERVER_PORT and with --server.port
  • State the precedence between same-location properties and yml files

Architectural & Technical Review

Core Interview Questions

Q01What is the precedence order between OS environment variables and packaged application.yml?Show answer

OS environment variables have higher precedence than application.yml (both default and profile-specific inside the JAR), allowing container orchestrators like Docker and Kubernetes to override settings without rebuilding the artifact.

Q02What are the main architectural differences between application.properties and application.yml?Show answer

Properties files use flat key-value pairs and are supported by standard @PropertySource. YAML provides human-readable hierarchical structures, native lists, and multi-document profile separation (---), but requires careful indentation and string quoting to avoid YAML 1.1 boolean type coercion.

Q03How does Spring Boot relaxed binding map environment variables to property keys?Show answer

Dots and hyphens are converted to underscores, array indices [n] become _n_, and names are converted to uppercase screaming snake (e.g. server.port -> SERVER_PORT, app.payment-service.api-key -> APP_PAYMENT_SERVICE_API_KEY).

Production Pitfalls

Critical Anti-Patterns

  • Pitfall: Assuming packaged YAML overrides environment variables — External environment variables always take precedence over packaged configuration by design.
  • Pitfall: Implicit YAML boolean coercion on unquoted strings — Unquoted country codes or keys like "NO", "yes", "on", or "off" are coerced into booleans by YAML 1.1 parsers.

Primary Documentation & Specifications

Supplementary Module Resources