Spring Boot’s externalized configuration is a powerful mechanism for managing application settings, and application.yml along with profiles is a cornerstone of this system.

Imagine you have a Spring Boot application that needs to connect to a database. You’ve got your database URL, username, and password all hardcoded in your application’s Java code. Now, you need to deploy this application to three different environments: development, staging, and production. Each environment has its own distinct database credentials. Without externalized configuration, you’d be looking at creating three separate builds of your application, each with different hardcoded values. This is obviously unmanageable and error-prone.

Spring Boot’s externalized configuration, primarily through application.yml and profiles, solves this by allowing you to define your configurations outside of your application’s code. This means you can have a single, deployable artifact that behaves differently based on the environment it’s running in.

Let’s see this in action.

Consider a simple Spring Boot application that prints a greeting. We’ll use application.yml to define the greeting message.

First, create a file named application.yml in the src/main/resources directory of your Spring Boot project.

# src/main/resources/application.yml
greeting:
  message: "Hello from the default configuration!"

Now, in your main application class, inject and use this property:

// src/main/java/com/example/demo/DemoApplication.java
package com.example.demo;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.stereotype.Component;

@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

    @Component
    public static class GreetingRunner implements CommandLineRunner {

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

        @Override
        public void run(String... args) throws Exception {
            System.out.println(greetingMessage);
        }
    }
}

When you run this application, you’ll see:

Hello from the default configuration!

This is the default configuration loaded from application.yml. But what if you need a different greeting for your production environment? This is where profiles come in.

Profiles allow you to create environment-specific configurations. You can define profile-specific YAML files that will be loaded when a particular profile is active.

Let’s create a production profile configuration. Create a new file named application-production.yml in the src/main/resources directory:

# src/main/resources/application-production.yml
greeting:
  message: "Welcome to the production environment!"

Now, to activate this profile, you have several options. The most common way is to set the spring.profiles.active property. You can do this in application.yml itself, via environment variables, or command-line arguments.

Option 1: Setting in application.yml (for development/testing purposes, not recommended for production)

You can set a default active profile in your main application.yml:

# src/main/resources/application.yml
spring:
  profiles:
    active: production

greeting:
  message: "Hello from the default configuration!" # This will be overridden by production

If you run the application with this change, you’ll see:

Welcome to the production environment!

Option 2: Environment Variable

This is a more common and flexible approach for production deployments. Before running your application, set an environment variable:

On Linux/macOS:

export SPRING_PROFILES_ACTIVE=production
java -jar your-app.jar

On Windows (Command Prompt):

set SPRING_PROFILES_ACTIVE=production
java -jar your-app.jar

On Windows (PowerShell):

$env:SPRING_PROFILES_ACTIVE="production"
java -jar your-app.jar

When the application starts, Spring Boot will detect the SPRING_PROFILES_ACTIVE environment variable and load the application-production.yml configuration, overriding any properties defined in the default application.yml for the same keys.

Option 3: Command-line Argument

You can also pass the active profile directly when running the application:

java -jar -Dspring.profiles.active=production your-app.jar

This command-line argument takes precedence over environment variables and application.yml.

The Order of Precedence

Spring Boot has a well-defined order of precedence for loading properties. When you have multiple configuration sources, the one higher in the list wins. Generally, it looks something like this (simplified):

  1. java -jar command-line arguments (--property=value)
  2. Spring Boot command-line arguments (-Dproperty=value)
  3. ServletConfig init parameters
  4. ServletContext init parameters
  5. JNDI attributes
  6. Java System properties (System.getProperties())
  7. OS environment variables
  8. application-{profile}.properties or application-{profile}.yml
  9. application.properties or application.yml
  10. @PropertySource annotations on @Configuration classes
  11. Default properties (e.g., from spring-boot-autoconfigure.jar)

In our case, application-production.yml (item 8) overrides application.yml (item 9) for the greeting.message property when production is active.

The Mental Model

Think of application.yml as your baseline configuration – the settings that apply to all environments unless overridden. Then, application-{profile}.yml files are your environment-specific overrides. When you activate a profile, you’re essentially telling Spring Boot, "Load this specific set of overrides on top of the baseline."

The greeting.message property in application.yml is a standard key-value pair. Spring Boot’s property binding mechanism, using @Value or @ConfigurationProperties, maps these keys to your Java objects. When the production profile is active, Spring Boot finds the greeting.message key in application-production.yml and uses that value instead of the one in application.yml.

You can have multiple profiles active simultaneously. For instance, you might have a web profile and a production profile. Spring Boot would then load application-web.yml and application-production.yml, merging their properties. If a property exists in both, the one from the profile that is later in the active list (or has higher precedence) would win.

The most surprising true thing about Spring Boot externalized configuration is how seamlessly it integrates with external systems like Kubernetes ConfigMaps and Secrets. You can mount these as files within your container, and Spring Boot will automatically pick them up as configuration sources, respecting the same precedence rules. This means your application’s configuration can be managed entirely outside the application artifact and its container image, making deployments and updates significantly more agile.

The next concept you’ll likely encounter is using @ConfigurationProperties for more structured configuration binding, which offers compile-time checks and better type safety than simple @Value annotations.

Want structured learning?

Take the full Spring-boot course →