Skip to main content

Welcome to a Grasp lesson

Create a free account to keep studying and create your own study path.

Lesson 63

Spring Profiles for Environment-Specific Configurations

Recommended resources

Hello! Welcome back to our module on "Advanced Configuration, Caching, & Monitoring."

In our last lesson, we explored how to externalize configuration using application.yml and environment variables. This is a crucial first step toward creating flexible and secure applications. However, as applications grow and move through different environments—from your local machine (development) to a testing server (QA) and finally to live users (production)—managing individual environment variables can become complex and error-prone.

Today, we'll address this challenge head-on. This lesson covers Spring Profiles, a powerful feature designed to organize and manage environment-specific configurations cleanly. Our goal is to learn how to configure multiple environments, such as dev and prod, allowing you to switch between them effortlessly.

1. Why Do We Need Different Environments?

In professional software development, you never run the exact same configuration on your local machine as you do in production. Each environment has unique requirements.

For example:

  • Development (dev): You might use an in-memory database (like H2) for fast startups, enable detailed DEBUG logging to trace issues, and connect to test APIs.
  • Production (prod): You'll connect to a robust, persistent database (like PostgreSQL), set logging to INFO or ERROR to reduce noise, and use real, production-level API endpoints.

Manually changing these settings before each deployment is not just tedious; it's a recipe for disaster. Spring Profiles solve this by letting you group these settings into logical "profiles."

Spring Boot Profiles: Managing Multiple Environments Like a Pro

To see a clear breakdown of why this is necessary, let's start with the article "Spring Boot Profiles: Managing Multiple Environments Like a Pro" by Igor Venturelli.

Please read the section "Why Do You Need Spring Boot Profiles?". The table comparing Dev, Staging, and Production environments perfectly illustrates the problem we are solving today.


2. Defining Profile-Specific Configurations

Now that we understand the "why," let's look at the "how." Spring Boot offers two primary ways to define properties for different profiles. Since we focused on YAML in the last lesson, we'll continue with that format.

Method 1: Using Separate application-{profile}.yml Files

One common approach is to create a separate YAML file for each environment. Spring Boot automatically recognizes files that follow the application-{profile}.yml naming convention.

You would structure your src/main/resources directory like this:

  • application.yml (for common properties shared across all profiles)
  • application-dev.yml (for properties specific to the dev profile)
  • application-prod.yml (for properties specific to the prod profile)

When a profile (e.g., dev) is active, Spring Boot first loads application.yml and then loads application-dev.yml. Any properties defined in application-dev.yml will override the same properties from application.yml.

Example:

src/main/resources/application.yml (Common settings)

server:
  port: 8080 # Default port

app:
  welcome-message: "Hello from the default profile!"

src/main/resources/application-prod.yml (Production-specific overrides)

spring:
  datasource:
    url: jdbc:postgresql://prod-db:5432/mydb
    username: prod_user
    password: ${PROD_DB_PASSWORD}

logging:
  level:
    com.example.myapp: INFO

app:
  welcome-message: "Welcome to our application!" # Overrides the default message

This method is very organized, as each environment's configuration is neatly contained in its own file.

Method 2: Using a Single, Multi-Document application.yml

A more modern and often more convenient approach is to define all your profiles within a single application.yml file. You can separate different profile configurations using three hyphens (---).

To specify which profile a block of configuration belongs to, you use the spring.config.activate.on-profile property.

Spring Boot Profiles: Managing Multiple Environments Like a Pro

The official Spring Boot documentation and the Venturelli article both provide excellent examples of this multi-document structure. Let's look at how to set this up.

First, review the section "Using YAML for Profile-Based Configuration" in the Venturelli article. It shows a complete example of a multi-document file.

Properties and Configuration :: Spring Boot

Next, for a more technical explanation, look at the official Spring Boot documentation.

Read the section "Change Configuration Depending on the Environment". It formally introduces the spring.config.activate.on-profile property and shows both Properties and YAML formats.

Here's how you can structure a single application.yml to combine default, dev, and prod configurations:

src/main/resources/application.yml

# --- Document 1: Common properties for ALL profiles ---
server:
  port: 8080
logging:
  level:
    com.example.myapp: DEBUG # Default to DEBUG logging

---
# --- Document 2: 'dev' profile specific properties ---
spring:
  config:
    activate:
      on-profile: "dev"
app:
  welcome-message: "Welcome, Developer!"
spring:
  datasource:
    url: jdbc:h2:mem:testdb # In-memory H2 database
    username: sa
    password:

---
# --- Document 3: 'prod' profile specific properties ---
spring:
  config:
    activate:
      on-profile: "production" # It's common to use 'production' or 'prod'
server:
  port: 80 # Production servers often run on standard ports
logging:
  level:
    com.example.myapp: INFO # More concise logging in prod
spring:
  datasource:
    url: jdbc:postgresql://prod-db:5432/mydb
    username: prod_user
    password: ${DB_PROD_PASSWORD} # Use environment variable for security

In this setup, the first block (before any ---) contains default properties. The subsequent blocks are only activated if their respective profile is enabled. This keeps all environment configuration in one place.


3. Activating a Spring Profile

Defining profiles isn't enough—you need to tell Spring Boot which one to activate. Spring follows the same property override hierarchy we discussed in the previous lesson. Here are the most common ways to activate a profile, from lowest to highest precedence.

Spring Boot Profiles: Managing Multiple Environments Like a Pro

The article by Igor Venturelli clearly outlines the main methods for setting the active profile. Understanding these is key to deploying and running your application correctly.

Read the section "How to Set the Active Profile". Focus on the three methods: using application.properties (or .yml), command-line arguments, and environment variables.

Let's summarize these methods:

  1. In application.yml (Lowest Precedence):
    You can set a default active profile directly in your main application.yml. This is great for local development, as you don't have to specify it every time you run the app.

    spring:
      profiles:
        active: "dev"
    
  2. Environment Variable (Medium Precedence):
    This is the standard for cloud and container-based deployments (like Docker). You set an environment variable named SPRING_PROFILES_ACTIVE. This will override the value set in application.yml.

    export SPRING_PROFILES_ACTIVE=production
    java -jar my-app.jar
    
  3. Command-Line Argument (Highest Precedence):
    You can also specify the active profile when running the application from the command line. This overrides both the environment variable and the YAML property.

    java -jar my-app.jar --spring.profiles.active=production
    

This hierarchy gives you the flexibility to set a sensible default for development while allowing deployment scripts and cloud environments to easily override it for production.

Profiles In Spring & Spring Boot Overview
This diagram provides a great visual summary of what Spring Profiles are, why they are used, and how to create and activate them, reinforcing the concepts we've just covered.
Test your understanding!

You are building an application that needs a dev and a qa profile.

  • Common: The server port should be 8888 for both profiles.
  • dev profile: The database should be an in-memory H2 database (jdbc:h2:mem:devdb).
  • qa profile: The database should be a MySQL instance at jdbc:mysql://qa-db/app_db and the logging level for your application's package (com.mycompany) should be INFO.

Write a single, multi-document application.yml file to implement this configuration.

Show answer
# Common properties
server:
  port: 8888

---
# 'dev' profile configuration
spring:
  config:
    activate:
      on-profile: "dev"
  datasource:
    url: jdbc:h2:mem:devdb
    username: sa
    password:

---
# 'qa' profile configuration
spring:
  config:
    activate:
      on-profile: "qa"
  datasource:
    url: jdbc:mysql://qa-db/app_db
    username: qa_user
    password: ${DB_QA_PASSWORD}
logging:
  level:
    com.mycompany: INFO

Conclusion

You've now learned how to use Spring Profiles to create clean, manageable, and environment-specific configurations. This is a fundamental skill for building professional, production-ready backend applications.

Key Takeaways:

  • Spring Profiles are used to segregate parts of your application configuration and make them available only in certain environments.
  • You can define profiles in separate application-{profile}.yml files or within a single, multi-document application.yml file using the --- separator.
  • Properties in a profile-specific configuration override properties from the default configuration.
  • Profiles are activated using the spring.profiles.active property, which can be set in application.yml, as an environment variable, or as a command-line argument, with higher-precedence sources overriding lower-precedence ones.

What's Next?

So far, we have only used profiles to change property values (like database URLs and logging levels). But what if you need to change the application's behavior more fundamentally? For instance, using a real email service in production but a mock, logging-based service in development.

In the next lesson, we will learn how to use the @Profile annotation. This powerful tool lets you conditionally register entire Java beans in the Spring container based on the active profile, giving you full control over your application's components in different environments.