Hello! Welcome to the next lesson in our journey through Spring Boot's core concepts.
In our last lesson, we demystified auto-configuration and saw how Spring Boot uses annotations like @ConditionalOnProperty to intelligently configure your application based on its environment. This naturally raises a crucial question for any real-world application: how exactly does Spring Boot find and manage these properties, especially when you need different settings for development, testing, and production?
Today, we'll answer that question. The goal for this lesson is to learn how to implement externalized and profile-specific configuration in a Spring Boot application. Mastering this is non-negotiable for building deployable, maintainable systems and is a frequent topic in senior-level interviews. You will learn to control your application's behavior across different environments without ever changing its code.
1. Externalized Configuration: The "Why"
The fundamental principle is to externalize configuration—that is, to move configuration details (like database URLs, API keys, server ports) outside of your application's packaged code (the JAR file). This allows the same application artifact to be deployed and run in any environment simply by providing the correct configuration at runtime.
Spring Boot makes this easy by searching for properties in a variety of locations. The key to understanding this system is to know the order of precedence. When the same property is defined in multiple places, which one wins?
2. The Hierarchy of Property Sources
Spring Boot searches for properties in a specific, hierarchical order. A property from a source with higher priority will always override the same property from a source with lower priority.
To get a clear, interview-ready understanding of this hierarchy, let's start with a focused article.
Spring Boot @Value Property Order Explained - Ashutosh Writes
The article 'Spring Boot @Value Property Order Explained' from Ashutosh Writes provides a concise and practical overview of the property resolution order. This is a great starting point for understanding the most common sources.
Please read the sections 'Understanding the @Value Annotation' and 'Where Does Spring Boot Look for Properties (Order of Resolution)'. Pay close attention to the table that lists the property sources and their priority. The mnemonic provided at the end is particularly useful for interviews.
The article gives you a simplified but powerful mental model. The most important sources, from highest to lowest priority, are:
- Command-line arguments: Passed when you run the application (e.g.,
java -jar app.jar --server.port=9000). These have the highest priority and are perfect for one-off overrides. - Java System properties: Passed via the
-Dflag (e.g.,java -Dserver.port=9000 -jar app.jar). - OS environment variables: Set in your operating system (e.g.,
export SERVER_PORT=9000). This is a common way to configure applications in containerized environments like Docker and Kubernetes. Note that Spring Boot uses "relaxed binding," so an environment variableMY_APP_API_KEYwill correctly map to a propertymy.app.api-key. - Application configuration files: These are your
application.propertiesorapplication.ymlfiles, located inside or outside your JAR.
This hierarchy is designed for maximum flexibility. You can bake sensible defaults into your application.properties, and operations teams can override them with environment variables or command-line arguments without ever touching the application code.
The official Spring Boot documentation provides the most comprehensive list of property sources. While you don't need to memorize all 15+ sources, it's good to know that the hierarchy is extensive and well-documented. The key takeaway is that sources external to your JAR (like command-line arguments) have higher precedence than sources packaged within it.
3. Implementing Profile-Specific Configuration
While overriding individual properties is useful, you typically need to change a whole group of properties for a given environment. This is where profiles come in. A profile is a named set of properties that you can activate to configure your application for a specific environment like dev, qa, or prod.
You create profile-specific configurations by creating files with the naming convention application-{profile}.properties.
application.properties(contains common or default properties)application-dev.properties(contains properties specific to the 'dev' environment)application-prod.properties(contains properties for the 'production' environment)
When a profile is active, Spring Boot loads both the default application.properties and the profile-specific file. Properties in the profile-specific file will override those in the default file.
Activating a Profile
You can activate a profile using the spring.profiles.active property. Since this property itself is subject to the hierarchy we just discussed, you have several options:
- In
application.properties:spring.profiles.active=dev - As a command-line argument (highest priority):
java -jar myapp.jar --spring.profiles.active=prod - As an environment variable:
export SPRING_PROFILES_ACTIVE=prod java -jar myapp.jar
Let's see a practical demonstration of how this works.
Spring Boot @Value Property Order Explained - Ashutosh Writes
The 'Ashutosh Writes' article provides a simple, clear example of how default, profile-specific, and command-line properties interact.
Read the section 'Example Demonstration'. Follow the four cases to see how Spring Boot injects different values for my.property depending on whether a profile is active or if a command-line argument is supplied.
Test your understanding!
You have the following configuration files:
application.properties:
server.port=8080
db.url=jdbc:h2:mem:defaultdb
application-prod.properties:
server.port=80
db.url=jdbc:postgresql://prod-host/maindb
You run your application with the following command:java -jar myapp.jar --spring.profiles.active=prod --server.port=443
What will be the final values for server.port and db.url in your running application? Why?
Show answer
server.portwill be443. The command-line argument has the highest priority, overriding the value in bothapplication-prod.properties(80) andapplication.properties(8080).db.urlwill bejdbc:postgresql://prod-host/maindb. Theprodprofile is active, so the value fromapplication-prod.propertiesoverrides the default value fromapplication.properties. There is no command-line override for this property.
4. Advanced Techniques and Best Practices
For senior-level roles, you need to know more than just the basics. Let's cover two more advanced topics that are common in interviews and crucial for building robust applications.
@ConfigurationProperties vs. @Value
You've seen @Value used to inject single property values. However, for structured configuration (like database credentials or API settings), Spring provides a superior alternative: @ConfigurationProperties.
This annotation lets you bind a whole family of properties to a type-safe Java object.

Externalized Configuration :: Spring Boot
The official Spring Boot documentation provides the definitive guide to type-safe configuration properties. This is a must-read for understanding modern Spring Boot configuration.
Read the section 'Type-safe Configuration Properties' and 'Relaxed Binding'. Focus on understanding: How to create a class annotated with @ConfigurationProperties. The benefits: grouping related properties, type-safety, and validation support. How 'constructor binding' allows for creating immutable configuration objects. How 'relaxed binding' lets you use different naming conventions (e.g., api-key in YAML vs. API_KEY as an environment variable) for the same field.
Key Interview Points: @ConfigurationProperties vs. @Value
- Use Case: Use
@Valuefor injecting single, simple values. Use@ConfigurationPropertiesfor structured, hierarchical properties (e.g.,app.security.jwt.secret). - Type Safety:
@ConfigurationPropertiesis strongly typed and can bind to complex objects, lists, and maps.@Valueis just for simple types. - Validation: You can use standard bean validation annotations (e.g.,
@NotNull,@Max) on fields in a@ConfigurationPropertiesclass, and Spring Boot will validate them on startup.@Valuedoes not support this. - Immutability:
@ConfigurationPropertiessupports constructor binding, allowing you to create immutable configuration objects, which is a best practice. - Flexibility:
@ConfigurationPropertiesoffers relaxed binding, making it easier to work with different property naming conventions from various sources (like environment variables).
Multi-Document Files
Instead of managing separate application-{profile}.properties files, you can use a single file and separate profile-specific sections within it. This is especially common with YAML.
Externalized Configuration :: Spring Boot
Let's look at how to structure a single configuration file for multiple profiles. This is a cleaner way to manage configurations for smaller projects.
Read the section 'Working With Multi-Document Files' and 'Activation Properties'. Notice the --- separator in YAML and the #--- separator for properties files. Also, see how spring.config.activate.on-profile is used to tie a document to a specific profile.
Here's a quick YAML example:
# Default properties, active for all profiles
server.port: 8080
---
# Properties active only when 'dev' profile is active
spring.config.activate.on-profile: dev
logging.level.com.example: DEBUG
---
# Properties active only when 'prod' profile is active
spring.config.activate.on-profile: prod
logging.level.com.example: INFO
This approach keeps all your environment configurations in one place, which can improve visibility.
Conclusion
You now have a solid framework for understanding and implementing configuration in a modern Spring Boot application. This is a core competency that separates junior developers from senior engineers who are trusted to build and deploy applications reliably.
Key Takeaways:
- Hierarchy is key: Spring Boot resolves properties based on a strict order of precedence, with external sources like command-line arguments overriding internal ones.
- Profiles for environments: Use profiles (
application-{profile}.propertiesandspring.profiles.active) to manage configurations for different environments like dev, QA, and production. - Prefer
@ConfigurationPropertiesfor structure: For anything more than a single value, use@ConfigurationPropertiesto gain type safety, validation, and immutable configuration objects. - Be flexible: Understand that configuration can come from property files, YAML files, environment variables, or command-line arguments, and know which one will win in a conflict.
Preview of the Next Lesson:
We've covered how beans are created, wired, and configured. But what if we want to add behavior to our beans—like logging or security checks—without modifying their source code? In our next lesson, we will explore Aspect-Oriented Programming (AOP). You will learn how to explain Spring AOP concepts and implement a cross-cutting concern (e.g., logging) using an aspect, a powerful technique for keeping your business logic clean and your code modular.