Spring Boot Externalized Configuration

Complete Beginner-Friendly Chapter — Configure the Same Application for Dev, QA, Staging, and Production
Big idea: Externalized configuration means your application code stays the same while configuration values can change depending on the environment. Spring Boot can read configuration from properties files, YAML, environment variables, system properties, command-line arguments, JSON, configuration trees, and other sources.
Interview point: Externalized configuration is very important for Spring Boot interviews. You should know application.properties, YAML, profiles, property precedence, environment variables, @Value, @ConfigurationProperties, spring.config.location, and spring.config.import.

1. Why Externalized Configuration?

Imagine the same Spring Boot application is deployed to three environments:

EnvironmentDatabase URLServer Port
Developmentlocalhost database8080
QAQA database8081
ProductionProduction database80/443 through infrastructure

You do not want to change Java code every time the environment changes.

Same Java Code + Different Config Different Environment

2. Main Ways to Provide Configuration

Spring Boot supports many configuration sources, including:

  • application.properties
  • application.yaml / application.yml
  • Profile-specific files
  • Environment variables
  • Java system properties
  • Command-line arguments
  • SPRING_APPLICATION_JSON
  • JNDI properties
  • Servlet context/config parameters
  • Test-specific properties
  • Configuration trees
  • Imported configuration locations

Spring Boot combines these sources into Spring's Environment. Later, higher-precedence sources can override values from earlier sources.

3. The Spring Environment

Think of the Environment as a large configuration box:

application.properties YAML Environment variables System properties CLI args JSON Tests → Environment

You can access values using:

ApproachBest for
@ValueSmall number of individual values
EnvironmentProgrammatic access to properties
@ConfigurationPropertiesGroups of related configuration values

4. The Most Common File: application.properties

A normal Spring Boot project can have:

src/main/resources/application.properties

Example:

server.port=8080
spring.application.name=my-api

app.message=Hello Spring Boot
app.max-users=100

Spring Boot automatically loads standard application configuration files from its supported config locations.

5. YAML Configuration

You can also use YAML:

server:
  port: 8080

spring:
  application:
    name: my-api

app:
  message: Hello Spring Boot
  max-users: 100

YAML is especially convenient when configuration is hierarchical.

Best practice: Pick one format for an application and stick with it. If both .properties and YAML exist in the same location, the properties format takes precedence.

6. Property Precedence — Very Important

Spring Boot uses a specific PropertySource order. A source later in the order can override a value supplied by an earlier source.

OrderSource
1Default properties from SpringApplication.setDefaultProperties(Map)
2@PropertySource annotations
3Config data such as application.properties
4RandomValuePropertySource for random.*
5OS environment variables
6Java system properties
7JNDI attributes
8ServletContext init parameters
9ServletConfig init parameters
10SPRING_APPLICATION_JSON / spring.application.json
11Command-line arguments
12Test properties attribute
13@DynamicPropertySource
14@TestPropertySource
15Devtools global settings
Easy rule: When two sources define the same key, the value from the higher-precedence source wins.

7. A Simple Override Example

Suppose application.properties contains:

server.port=8080

Now start the application with:

java -jar app.jar --server.port=9000

The command-line value wins, so the application uses:

server.port=9000

Command-line properties are added to the Spring Environment by default and have higher precedence than file-based configuration.

8. Disable Command-Line Properties

If you do not want command-line options to be added to the Environment, configure:

SpringApplication application =
        new SpringApplication(MyApplication.class);

application.setAddCommandLineProperties(false);

application.run(args);

9. External Application Properties

Spring Boot automatically searches for application.properties and application.yaml in several standard locations.

AreaLocation
ClasspathClasspath root
ClasspathClasspath /config
Current directory./
Current directory./config/
Current directoryImmediate child directories of ./config/

External configuration locations have higher precedence than earlier default locations, allowing deployment-specific values to override packaged defaults.

10. Why Put Configuration Outside the JAR?

Suppose your JAR contains:

application.properties

server.port=8080
app.environment=default

On the production server, you can provide:

./config/application.properties

app.environment=production
server.port=9090

You can deploy the same JAR to multiple environments without rebuilding it.

Production pattern:
Build once → deploy the same artifact → inject environment-specific configuration at runtime.

11. Change the Configuration File Name

By default, Spring Boot looks for the application basename.

You can change it with:

java -jar myproject.jar --spring.config.name=myproject

Spring Boot can then look for:

myproject.properties
myproject.yaml
spring.config.name is needed very early during startup, so it must be supplied as an environment property, system property, or command-line argument.

12. spring.config.location

spring.config.location lets you explicitly tell Spring Boot where to search for configuration.

java -jar app.jar \
  --spring.config.location=optional:classpath:/default.properties,optional:classpath:/override.properties

It accepts a comma-separated list of locations.

Important: spring.config.location replaces the default search locations. It does not simply add another location.

13. spring.config.additional-location

If you want to keep the normal default locations and add more locations, use:

java -jar app.jar \
  --spring.config.additional-location=optional:file:./custom-config/
PropertyEffect
spring.config.locationReplaces the default locations.
spring.config.additional-locationAdds extra locations after the defaults.
Remember: location = replace; additional-location = add.

14. optional: Locations

By default, a configured location that does not exist can cause:

ConfigDataLocationNotFoundException

If a location is optional, prefix it with:

optional:

Example:

spring.config.import=optional:file:./myconfig.properties

Now the application can start even if that file does not exist.

15. Ignore ConfigDataLocationNotFoundException

You can configure Spring Boot to ignore all missing config-data location errors:

spring.config.on-not-found=ignore

This can also be configured through SpringApplication.setDefaultProperties(...).

16. Wildcard Locations

Wildcard locations are useful when configuration is split across multiple directories.

Example:

/config/
  redis/
    application.properties
  mysql/
    application.properties

A wildcard location such as:

config/*/

allows the immediate subdirectories to be searched.

Useful for Kubernetes: separate configuration sources can be mounted under different directories, while Spring Boot loads them together.

Spring Boot includes config/*/ among its default external search locations.

17. Profile-Specific Configuration

Spring Boot supports profile-specific files using:

application-{profile}.properties
application-{profile}.yaml

Example:

application.properties
application-dev.properties
application-qa.properties
application-prod.properties

Activate a profile

spring.profiles.active=prod

Or:

java -jar app.jar --spring.profiles.active=prod

How override works

If application.properties says:

app.message=Default message

and application-prod.properties says:

app.message=Production message

with the prod profile active, the production value overrides the default value.

18. Multiple Active Profiles

You can activate multiple profiles:

spring.profiles.active=prod,live

When multiple profiles are active, a last-wins strategy applies at the location-group level. Values from the later profile can override earlier profile values.

Example: prod,live → if both define app.message, the live value can override the prod value.

19. Location Groups

When using spring.config.location, commas and semicolons have different meanings.

SeparatorMeaning
,Locations are processed in sequence.
;Locations belong to the same location group.

Example:

spring.config.location=classpath:/cfg/,classpath:/ext/

Compared with:

spring.config.location=classpath:/cfg/;classpath:/ext/

This becomes especially important when profile-specific files exist in multiple locations.

20. Property Placeholders

Configuration values can refer to other configuration values using:

${name}

Example:

app.name=My Store
app.welcome=Welcome to ${app.name}

The resulting value of app.welcome becomes:

Welcome to My Store

Default value

app.timeout=${TIMEOUT:30}

This means:

  • Use TIMEOUT if it exists.
  • Otherwise use 30.

21. Reading Properties with @Value

@Value is useful when you need one or two values.

@Component
public class MyBean {

    @Value("${app.message}")
    private String message;

    @Value("${app.max-users}")
    private int maxUsers;
}

Configuration:

app.message=Hello
app.max-users=100
For a small number of unrelated values, @Value is simple. For a group of related application settings, @ConfigurationProperties is usually cleaner.

22. Reading Properties with Environment

@Component
public class MyService {

    private final Environment environment;

    public MyService(Environment environment) {
        this.environment = environment;
    }

    public void printConfig() {
        String url =
            environment.getProperty("app.url");

        System.out.println(url);
    }
}

This approach is useful when you need programmatic or dynamic property lookup.

23. @ConfigurationProperties — The Better Approach for Groups

Suppose you have:

app:
  name: My Store
  url: https://example.com
  timeout: 30s
  max-users: 100

Create a configuration object:

@ConfigurationProperties(prefix = "app")
public class AppProperties {

    private String name;
    private String url;
    private Duration timeout;
    private int maxUsers;

    // getters and setters
}

Then use it in your service:

@Service
public class MyService {

    private final AppProperties properties;

    public MyService(AppProperties properties) {
        this.properties = properties;
    }

    public void connect() {
        System.out.println(properties.getUrl());
    }
}
Easy memory:
@Value → one/few values
@ConfigurationProperties → a complete configuration group

24. Type-Safe Configuration

One major advantage of @ConfigurationProperties is that configuration can map into Java types instead of leaving everything as strings.

ConfigurationJava type
timeout: 30sDuration
max-users: 100int
Boolean propertyboolean
URL-like valueAppropriate structured type where supported
List valuesList<T>
Map valuesMap<K,V>

25. Constructor Binding

Configuration properties can also be represented using immutable objects and constructor-based binding.

@ConfigurationProperties("app")
public class AppProperties {

    private final String name;
    private final int maxUsers;

    public AppProperties(String name, int maxUsers) {
        this.name = name;
        this.maxUsers = maxUsers;
    }

    public String getName() {
        return name;
    }

    public int getMaxUsers() {
        return maxUsers;
    }
}

This style is useful when you want configuration objects that should not be modified after creation.

26. Relaxed Binding

Spring Boot's configuration-property binding is flexible about common naming conventions.

StyleExample
Kebab casemax-users
Environment variable styleMAX_USERS
Typical Java camelCasemaxUsers

For environment variables, periods are generally replaced with underscores, and naming is commonly converted to uppercase.

spring.config.name

becomes:

SPRING_CONFIG_NAME

27. Environment Variables

Environment variables are especially useful in Docker and Kubernetes.

export SERVER_PORT=8085
export SPRING_PROFILES_ACTIVE=prod

Spring Boot can map these environment variables to configuration properties.

Container pattern:
Application image stays unchanged → environment variables supply deployment-specific settings.

28. SPRING_APPLICATION_JSON

You can place multiple properties inside one JSON object.

SPRING_APPLICATION_JSON='{"my":{"name":"test"}}' java -jar myapp.jar

Spring Boot exposes this as:

my.name=test

The same JSON can be supplied as a Java system property:

java -Dspring.application.json='{"my":{"name":"test"}}' -jar myapp.jar

Or as a command-line argument:

java -jar myapp.jar --spring.application.json='{"my":{"name":"test"}}'
A JSON null is treated as a missing value by Spring's property resolver, so JSON cannot override a lower-precedence property with null.

29. Importing Configuration with spring.config.import

spring.config.import allows one configuration file to import another configuration source.

spring.config.import=optional:file:./myconfig.properties

This is useful when configuration is split into separate files or comes from another supported configuration source.

application.properties spring.config.import external config Environment

30. Import Extensionless Files

Some cloud platforms mount files without file extensions. Spring Boot lets you provide an extension hint.

spring.config.import=file:/etc/config/myconfig[.yaml]

Equivalent explicit form:

spring.config.import=file:/etc/config/myconfig[extension=.yaml]

Multiple attributes can also be supplied:

spring.config.import=file:/etc/config/myconfig[extension=.yaml][encoding=utf-8]

31. Importing Environment Variables as Configuration

Spring Boot can treat the contents of an environment variable as a configuration file.

Suppose:

MY_CONFIGURATION="
my.name=Service1
my.cluster=Cluster1
"

Then:

spring.config.import=env:MY_CONFIGURATION

The imported properties become part of the Spring Environment.

The default extension for this mechanism is .properties, and an extension can also be specified when needed.

32. Configuration Trees

Configuration trees are useful when secrets or configuration values are mounted as individual files, especially in Kubernetes or Docker.

Example directory:

/etc/config/
  myapp/
    username
    password

Import it with:

spring.config.import=optional:configtree:/etc/config/

The file names become property names.

myapp.username
myapp.password
Why this is useful: Secret managers or container platforms can mount secrets as files without putting the secret directly inside your application JAR.

33. Docker Secrets Example

Suppose Docker mounts a secret:

/run/secrets/db.password

Import the directory:

spring.config.import=optional:configtree:/run/secrets/

The property db.password becomes available to the Spring Environment.

34. Configuration Trees and Wildcards

Configuration trees can be combined with wildcard locations when configuration is split across mounted directories.

Directory names and file names under a configuration tree form property names. Dot notation in file names is also supported.

35. Encrypting Properties

Important: Spring Boot does not provide built-in encryption for property values.

Spring Boot does provide extension points such as EnvironmentPostProcessor that can modify values in the Spring Environment before the application starts.

For secure external secret storage, projects such as Spring Cloud Vault can be used.

Do not confuse externalized configuration with encrypted configuration. Externalization tells you where configuration comes from; encryption/secret management addresses how sensitive values are protected.

36. Third-Party Configuration

@ConfigurationProperties can also be applied to public @Bean methods. This is useful when configuring third-party components that you cannot modify.

@Bean
@ConfigurationProperties("my.datasource")
public DataSource dataSource() {
    return DataSourceBuilder.create().build();
}

This allows external configuration to bind into a third-party object.

37. Third-Party Prefixes

Use a meaningful prefix to group settings:

my:
  datasource:
    url: jdbc:mysql://localhost/shop
    username: app
    password: secret

Then bind:

@ConfigurationProperties("my.datasource")

38. Configuration Metadata

Spring Boot can generate configuration metadata for your own @ConfigurationProperties classes.

This metadata helps IDEs provide:

  • Auto-completion
  • Property descriptions
  • Known property names
  • Configuration hints
Developer experience: Good @ConfigurationProperties classes make configuration easier to discover and harder to mistype.

39. PropertySource vs Environment

ConceptMeaning
PropertySourceOne source of configuration values.
EnvironmentCombines property sources and resolves properties.
@ValueInjects a property into a bean.
@ConfigurationPropertiesBinds a group of properties to a structured object.

40. @PropertySource — Important Limitation

@PropertySource can add a property source, but it is added to the Environment only during context refresh.

This is too late for some properties such as logging.* and spring.main.*, which are read before the context refresh begins.

For normal Spring Boot application configuration, prefer the standard Config Data mechanisms such as application.properties, YAML, and spring.config.import.

41. Debugging “Why Did My Property Get This Value?”

When a property unexpectedly has a value, two useful Spring Boot Actuator endpoints are:

EndpointUseful for
envInspecting environment properties and property sources.
configpropsInspecting bound @ConfigurationProperties objects.

These are useful when debugging precedence and binding problems.

42. Complete Dev / QA / Prod Example

application.properties

spring.application.name=my-api
server.port=8080

app.name=My API
app.timeout=30s

application-dev.properties

app.environment=development
app.database-url=jdbc:postgresql://localhost/dev

application-qa.properties

app.environment=qa
app.database-url=jdbc:postgresql://qa-db/myapp

application-prod.properties

app.environment=production
app.database-url=jdbc:postgresql://prod-db/myapp

Run QA

java -jar app.jar --spring.profiles.active=qa

Override one value without changing files

java -jar app.jar \
  --spring.profiles.active=qa \
  --app.timeout=60s
Default config + QA profile + CLI override Final Environment

43. Kubernetes Mental Model

A common containerized architecture is:

Docker image application JAR ConfigMap Secret Environment variables Config tree Spring Environment

The application artifact remains the same while deployment infrastructure supplies environment-specific configuration.

44. Common Mistakes

MistakeBetter understanding
Hardcoding database URLs in Java.Externalize them.
Putting production passwords in Git.Use environment/secret management.
Confusing location and additional-location.location replaces defaults; additional-location adds to them.
Assuming a missing optional file should fail startup.Use optional: when absence is acceptable.
Using @Value for dozens of related properties.Prefer @ConfigurationProperties.
Assuming @PropertySource can configure every Boot property.Some properties are read before context refresh.
Assuming JSON null can override another source.Null is treated as missing by the property resolver.
Using different config formats everywhere.Prefer one format consistently.

45. Best Practices

  1. Keep environment-specific values outside application code.
  2. Use profiles for environment-specific groups of configuration.
  3. Use environment variables for container/deployment configuration.
  4. Use configuration trees for file-mounted secrets and configuration.
  5. Use @ConfigurationProperties for structured application settings.
  6. Use @Value for a small number of simple properties.
  7. Know precedence before debugging a surprising value.
  8. Use spring.config.additional-location when you want to preserve default locations.
  9. Use optional: only when missing configuration is genuinely acceptable.
  10. Do not put secrets into source control merely because externalized configuration is being used.

46. Quick Decision Guide

RequirementRecommended approach
One simple property@Value
Many related properties@ConfigurationProperties
Programmatic lookupEnvironment
Different environmentsProfiles
Docker/Kubernetes runtime valuesEnvironment variables
Mounted secretsConfiguration trees
Extra external config directoryspring.config.additional-location
Replace default config locationsspring.config.location
Optional imported fileoptional:
Multiple config sources inside one JSON valueSPRING_APPLICATION_JSON
Import another supported config sourcespring.config.import

47. Interview Questions

  1. What is externalized configuration in Spring Boot?
  2. Why should configuration be externalized?
  3. What is the Spring Environment?
  4. What is a PropertySource?
  5. Explain Spring Boot property precedence.
  6. Which has higher precedence: application.properties or a command-line argument?
  7. What is the difference between spring.config.location and spring.config.additional-location?
  8. What does the optional: prefix do?
  9. What are profile-specific configuration files?
  10. How do multiple active profiles override each other?
  11. What is relaxed binding?
  12. Difference between @Value and @ConfigurationProperties?
  13. When would you use Environment?
  14. What is SPRING_APPLICATION_JSON?
  15. What is spring.config.import?
  16. What is a configuration tree?
  17. How can Kubernetes secrets be exposed as Spring properties?
  18. Does Spring Boot provide built-in property encryption?
  19. What is the limitation of @PropertySource for logging.* and spring.main.*?
  20. How do you debug why a configuration property has a particular value?

48. Practice Exercises

Exercise 1: Create application.properties with server port, application name, and a custom app.message.
Exercise 2: Create application-dev.properties and application-prod.properties.
Exercise 3: Override a property using a command-line argument.
Exercise 4: Read one property using @Value.
Exercise 5: Read the same configuration group using @ConfigurationProperties.
Exercise 6: Set SPRING_PROFILES_ACTIVE=prod and explain what changes.
Exercise 7: Create an external config directory and load it with spring.config.additional-location.
Exercise 8: Create a configuration tree containing db.username and db.password.

49. Cheat Sheet

ConceptExample
Properties fileapplication.properties
YAMLapplication.yaml
Profileapplication-prod.properties
Activate profile--spring.profiles.active=prod
Custom basename--spring.config.name=myproject
Replace config locations--spring.config.location=...
Add config locations--spring.config.additional-location=...
Optional locationoptional:file:./config.properties
Import configspring.config.import=...
Environment variableSERVER_PORT=8080
JSON configurationSPRING_APPLICATION_JSON='{"app":{"name":"demo"}}'
Single value injection@Value("${app.name}")
Structured binding@ConfigurationProperties("app")
Programmatic lookupEnvironment#getProperty()
Mounted config/secretsconfigtree:/etc/config/

50. Memory Map

Externalized Config Environment PropertySource Properties YAML Profiles Environment Variables CLI @Value @ConfigurationProperties spring.config.import Config Tree Precedence

51. Final Takeaway

Remember this simple formula:

Same application code + external configuration = different environments.

application.properties / YAML → basic configuration
Profiles → environment-specific configuration
Environment variables → deployment/runtime configuration
Command-line arguments → quick high-precedence overrides
@Value → simple individual values
@ConfigurationProperties → structured configuration
spring.config.location → replace default locations
spring.config.additional-location → add locations
spring.config.import → import configuration
Config trees → mounted files/secrets
Property precedence → decides which value wins