Profiles Introduction

One App, Many Environments

Your laptop, the test server and production need different settings (database, log level, payment keys). A profile is a named set of settings. Put shared settings in application.yml and environment-specific ones in application-{profile}.yml.

application.yml          shared by all (app name, currency)
 application-dev.yml      local laptop: H2 / local MySQL, DEBUG logs, test payment keys
 application-prod.yml     production: real DB from env vars, INFO logs, live keys

Example

Shared

application.yml

spring:
  application:
    name: shopease
shopease:
  currency: INR
  payment-mode: sandbox

Production

application-prod.yml

server:
  port: 8080
shopease:
  payment-mode: live
logging:
  level:
    root: WARN

Example

Activate a profile with a property, environment variable or argument:

java -jar target/shopease-0.0.1-SNAPSHOT.jar --spring.profiles.active=prod
# or: SPRING_PROFILES_ACTIVE=prod java -jar target/shopease-0.0.1-SNAPSHOT.jar

Example output

... INFO ... ShopeaseApplication : The following 1 profile is active: "prod"

How Overriding Works

Example

Profile files are applied on top of the base file: same key, profile value wins. Simulated with maps:

import java.util.Map;
import java.util.TreeMap;

public class Main {
    static Map<String, String> load(String activeProfile) {
        Map<String, String> base = Map.of(
            "spring.application.name", "shopease",
            "shopease.payment-mode", "sandbox",
            "logging.level.root", "INFO");
        Map<String, Map<String, String>> profiles = Map.of(
            "dev", Map.of("logging.level.root", "DEBUG"),
            "prod", Map.of("shopease.payment-mode", "live", "logging.level.root", "WARN"));

        Map<String, String> effective = new TreeMap<>(base);
        effective.putAll(profiles.getOrDefault(activeProfile, Map.of()));   // profile overrides base
        return effective;
    }

    public static void main(String[] args) {
        for (String profile : new String[] { "default", "dev", "prod" }) {
            System.out.println(profile + " -> " + load(profile));
        }
    }
}

Output

default -> {logging.level.root=INFO, shopease.payment-mode=sandbox, spring.application.name=shopease}
dev -> {logging.level.root=DEBUG, shopease.payment-mode=sandbox, spring.application.name=shopease}
prod -> {logging.level.root=WARN, shopease.payment-mode=live, spring.application.name=shopease}

Note: Profile-specific beans (@Profile("prod")), multiple active profiles, @ConfigurationProperties and secrets from environment variables are covered in Configuration in Depth in the medium level.