Popular Searches
Popular Course Categories
Popular Courses

Implementing Environment-Specific Profiles

Implementing Environment-Specific Profiles

Spring Boot Application Development

Implementing Environment-Specific Profiles in Spring Boot

Course: Advanced Java Training

Topic: Implementing Environment-Specific Profiles

Course Link: Advanced Java Training at JustAcademy

Demo Link: Register for a Course Demo

JustAcademy Website: Visit JustAcademy


1. Introduction to Environment-Specific Profiles

Environment-specific profiles in Spring Boot allow developers to configure an application differently depending on where it runs. An application may need different database connections, server settings, logging levels, API endpoints, or security options in development, testing, staging, and production environments.

Instead of maintaining separate versions of the application for every environment, Spring Boot provides the profile mechanism. A profile activates a particular set of configuration properties and can also control which Spring beans are registered in the application context.

For example, developers may use an in-memory H2 database during local development, a dedicated test database during automated testing, and a managed database in production. Profiles help separate these settings while allowing the same application code to be deployed across environments.

Why Are Profiles Important?

  • Separate development, testing, staging, and production configuration.
  • Avoid accidentally connecting to production services during local development.
  • Use environment-appropriate database connections and API endpoints.
  • Change logging and diagnostic settings without modifying application code.
  • Enable or disable selected Spring beans for particular environments.
  • Make deployments easier to maintain and less error-prone.

2. Learning Objectives

  • Understand Spring profiles and their purpose.
  • Create profile-specific configuration files.
  • Activate profiles through properties, environment variables, command-line arguments, and deployment configuration.
  • Use the @Profile annotation to register environment-specific beans.
  • Understand default profiles and profile groups.
  • Manage external configuration and sensitive values safely.
  • Troubleshoot profile activation and configuration conflicts.

3. Understanding Common Application Environments

Environment Purpose Typical Configuration
Development Local development and debugging Local database, detailed logs, test services
Testing Automated tests and integration testing Isolated test database, predictable test data
Staging Pre-production verification Production-like infrastructure and settings
Production Serving real users Managed database, restricted diagnostics, secure credentials

The names are conventions, not mandatory Spring Boot keywords. You can name profiles according to your project requirements, such as local, qa, uat, or prod.

4. How Spring Profiles Work

Spring Boot loads application configuration from supported configuration sources, including configuration files, environment variables, command-line arguments, and external configuration locations. When a profile is active, Spring Boot can load profile-specific configuration and Spring can restrict bean registration according to profile conditions.

For example, the project may contain a common configuration file and additional files for individual environments:

src/main/resources/
├── application.properties
├── application-dev.properties
├── application-test.properties
├── application-staging.properties
└── application-prod.properties

The common application.properties file contains settings shared by environments. A profile-specific file contains settings that apply when its profile is active.

When the dev profile is active, Spring Boot uses the common configuration together with the applicable development configuration. Profile-specific values can override corresponding common values according to Spring Boot's configuration precedence rules.

5. Creating the Default Configuration File

The application.properties file is commonly used for shared settings and defaults. Create it inside src/main/resources.

# application.properties
spring.application.name=employee-management
server.port=8080

# Shared application configuration
app.name=Employee Management System
[email protected]

These settings apply broadly unless overridden by a higher-precedence configuration source or an applicable profile-specific setting.

For example, the application name and support email can remain common across environments, while database URLs and diagnostic logging settings can vary.

6. Creating a Development Profile

Create a file named application-dev.properties in the resources directory.

# application-dev.properties
server.port=8081

spring.datasource.url=jdbc:h2:mem:employee_dev
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=

spring.jpa.hibernate.ddl-auto=create-drop
spring.jpa.show-sql=true

logging.level.root=INFO
logging.level.com.example.employee=DEBUG

This example configures a local H2 database, enables SQL output for development, and uses a separate server port. It assumes that the H2 dependency is present in the project.

Important: The create-drop setting is intended for disposable development or test databases. Do not use it with a production database containing data that must be retained.

7. Creating a Test Profile

Create application-test.properties for automated testing or integration testing.

# application-test.properties
server.port=8082

spring.datasource.url=jdbc:h2:mem:employee_test
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=

spring.jpa.hibernate.ddl-auto=create-drop
spring.jpa.show-sql=false

logging.level.root=WARN
logging.level.com.example.employee=INFO

A separate test database helps isolate test data from development and production data. The database lifecycle and schema-generation settings should be chosen according to the testing strategy.

8. Creating a Production Profile

Create application-prod.properties for production-specific settings. Production configuration should favor secure credentials, managed services, restrained logging, and controlled schema changes.

# application-prod.properties
server.port=${SERVER_PORT:8080}

spring.datasource.url=${DB_URL}
spring.datasource.username=${DB_USERNAME}
spring.datasource.password=${DB_PASSWORD}

spring.jpa.hibernate.ddl-auto=validate
spring.jpa.show-sql=false

logging.level.root=INFO
logging.level.com.example.employee=INFO

Here, database settings are supplied through environment variables rather than being hard-coded into the project. The ${DB_URL}, ${DB_USERNAME}, and ${DB_PASSWORD} placeholders expect the deployment environment to provide corresponding values.

The validate setting checks whether the mapped schema is compatible with the application mappings; it does not automatically create or migrate the database schema. Production schema changes should generally be managed through a controlled migration process.

Never commit real production passwords, API keys, or other secrets to source control. Use an appropriate secret manager or secure deployment configuration.

9. Activating a Profile in application.properties

You can set the active profile in the common configuration file:

# application.properties
spring.profiles.active=dev

With this setting, the application activates the dev profile by default. This approach can be convenient locally, but explicitly setting a development profile in a shared deployment artifact can be risky if the artifact is later deployed to another environment.

For deployable applications, it is often preferable to select the profile through the environment, command line, or deployment platform.

10. Activating a Profile Through the Command Line

Spring Boot accepts configuration properties as command-line arguments. To activate the development profile, run the application with:

java -jar employee-management.jar --spring.profiles.active=dev

To activate the production profile:

java -jar employee-management.jar --spring.profiles.active=prod

Command-line configuration is useful for deployment scripts, containers, and local testing because the same packaged JAR can run with different profiles.

11. Activating a Profile Through an Environment Variable

Environment variables are commonly used in deployment platforms and containerized applications.

On Linux or macOS:

export SPRING_PROFILES_ACTIVE=dev
java -jar employee-management.jar

For production:

export SPRING_PROFILES_ACTIVE=prod
java -jar employee-management.jar

In Windows Command Prompt:

set SPRING_PROFILES_ACTIVE=dev
java -jar employee-management.jar

In PowerShell:

$env:SPRING_PROFILES_ACTIVE="dev"
java -jar employee-management.jar

Environment variables allow deployment infrastructure to choose the environment without requiring source-code changes. Make sure the variable is set in the same process environment from which the application starts.

12. Using YAML for Profile-Specific Configuration

Spring Boot also supports YAML configuration. A project can use YAML instead of properties files, provided configuration is organized consistently.

# application.yml
spring:
  application:
    name: employee-management

server:
  port: 8080

---
spring:
  config:
    activate:
      on-profile: dev
server:
  port: 8081
logging:
  level:
    com.example.employee: DEBUG

---
spring:
  config:
    activate:
      on-profile: prod
server:
  port: 8080
logging:
  level:
    com.example.employee: INFO

The three hyphens (---) separate YAML documents. The spring.config.activate.on-profile property specifies which profile activates a document.

Choose either a well-organized properties-file approach or a YAML approach based on project needs. Avoid maintaining duplicate settings in multiple files unless the precedence and purpose are clear.

13. Using the @Profile Annotation

The @Profile annotation controls whether a component or configuration class should be registered in the Spring application context for a particular profile.

For example, an application may use one notification service during development and a different implementation in production.

package com.example.employee.service;

public interface NotificationService {
    void sendNotification(String message);
}

Development implementation:

package com.example.employee.service;

import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Service;

@Service
@Profile("dev")
public class DevelopmentNotificationService
        implements NotificationService {

    @Override
    public void sendNotification(String message) {
        System.out.println("DEV notification: " + message);
    }
}

Production implementation:

package com.example.employee.service;

import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Service;

@Service
@Profile("prod")
public class ProductionNotificationService
        implements NotificationService {

    @Override
    public void sendNotification(String message) {
        // Integrate with an approved production notification provider.
        System.out.println("Production notification requested.");
    }
}

When the dev profile is active, Spring registers the development implementation. When the prod profile is active, Spring registers the production implementation.

In a real application, the production implementation should integrate with a properly configured provider, handle failures, and avoid logging sensitive message contents. If no active profile matches either implementation, an injection point requiring NotificationService may fail because no matching bean exists.

14. Applying Profiles to Configuration Classes

You can use @Profile on a configuration class to enable a complete group of beans for a particular environment.

package com.example.employee.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;

@Configuration
@Profile("dev")
public class DevelopmentConfiguration {

    @Bean
    public String environmentMessage() {
        return "Development environment is active";
    }
}

This configuration class is processed only when the dev profile matches. The bean in this example is illustrative; application-specific bean types are generally preferable to using a plain String as a Spring bean.

A production configuration can be defined separately using @Profile("prod"). This technique is useful for selecting environment-specific clients, mock integrations, or infrastructure adapters.

15. Profile Expressions and Multiple Profiles

Spring profile expressions allow more flexible matching than a single profile name.

Expression Meaning
@Profile("dev") Matches the dev profile.
@Profile("dev | test") Matches when either dev or test is active.
@Profile("!prod") Matches when prod is not active.
@Profile("dev & cloud") Matches when both dev and cloud are active.

Use profile expressions carefully. A broad condition such as !prod may match many environments, including environments that were not originally anticipated. Prefer explicit profile names when behavior must be tightly controlled.

16. Using Default Profiles

A default profile is used when no active profile has been explicitly selected. Spring's default profile name is default, but the default profile name can be changed with spring.profiles.default.

# application.properties
spring.profiles.default=dev

This example makes dev the default profile when no active profile is supplied. If an active profile is explicitly supplied, the default profile does not act as a substitute for that active profile.

For deployed applications, consider whether a development default is appropriate. In some systems, requiring the deployment platform to explicitly select the intended environment can reduce configuration mistakes.

17. Profile Groups

Profile groups allow one logical profile to activate a collection of related profiles. For example, a production profile might activate both production application settings and a cloud-specific configuration.

# application.properties
spring.profiles.group.production=prod,cloud

With this configuration, activating the production profile also activates the prod and cloud profiles.

java -jar employee-management.jar \
  --spring.profiles.active=production

Profile groups are useful for organizing configurations that must be activated together. Define groups in non-profile-specific configuration, not in a profile-specific document that is itself activated by the group.

18. Profile-Specific Database Configuration

Database configuration is one of the most common uses of environment-specific profiles. Each environment can point to a different database while keeping repository and service code unchanged.

# application-dev.properties
spring.datasource.url=jdbc:postgresql://localhost:5432/employee_dev
spring.datasource.username=${DEV_DB_USERNAME}
spring.datasource.password=${DEV_DB_PASSWORD}

# application-prod.properties
spring.datasource.url=${DB_URL}
spring.datasource.username=${DB_USERNAME}
spring.datasource.password=${DB_PASSWORD}

The development example assumes PostgreSQL is available locally and the required JDBC driver is included. Production variables should be injected by the deployment environment or a secure secrets system.

Never rely on the profile alone as a security boundary. Database permissions, network access, credentials, and production safeguards must be enforced independently.

19. Externalized Configuration and Property Precedence

Spring Boot supports multiple configuration sources. When the same property appears in more than one source, the value selected depends on the documented property-source precedence.

Common sources include:

  • Packaged application configuration files.
  • Profile-specific configuration files.
  • Operating-system environment variables.
  • Java system properties.
  • Command-line arguments.
  • External configuration files and other supported property sources.

For example, the following command-line argument can override the port defined in a configuration file:

java -jar employee-management.jar \
  --spring.profiles.active=dev \
  --server.port=9090

Do not assume that a particular file always wins in every situation. Check the Spring Boot documentation for the exact precedence rules for the version being used, especially when configuration imports, environment variables, command-line arguments, or external files are involved.

20. Restricting Profile Activation Properties

Properties such as spring.profiles.active and spring.profiles.default are used to determine profile selection and must be specified in non-profile-specific configuration sources. They should not be placed inside a profile-specific document to try to activate another profile from that document.

Use command-line arguments, environment variables, or a base configuration file to select active profiles. Keep profile-specific files focused on settings that apply after a profile has been selected.

21. Testing Environment-Specific Behavior

Profile-specific behavior should be tested to ensure the correct beans and settings are used. Spring Boot tests can activate a profile with @ActiveProfiles.

package com.example.employee;

import com.example.employee.service.NotificationService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;

import static org.junit.jupiter.api.Assertions.assertNotNull;

@SpringBootTest
@ActiveProfiles("dev")
class DevelopmentProfileTest {

    @Autowired
    private NotificationService notificationService;

    @Test
    void developmentNotificationServiceIsAvailable() {
        assertNotNull(notificationService);
    }
}

This test checks that the application context starts with the development profile and that a NotificationService bean is available. For stronger verification, test the expected implementation or observable behavior rather than only checking for a non-null reference.

Keep test configuration isolated. A test profile should not accidentally point to a production database or send messages to real customers.

22. Common Errors and Troubleshooting

Problem Possible Cause Solution
Profile-specific settings are ignored Profile name is misspelled or not active. Check the file name and verify the active profile at startup.
Application fails during startup A required environment variable is missing. Set the variable or provide a suitable non-secret default where appropriate.
No matching service bean exists No active profile matches the bean's @Profile condition. Activate the intended profile or define a safe fallback implementation.
Unexpected database is selected A higher-precedence property source overrides the intended URL. Inspect command-line arguments, environment variables, and configuration sources.
Production uses development settings The deployment environment activates the wrong profile or contains conflicting values. Review deployment configuration and validate the effective settings safely.
Duplicate bean definition or ambiguous injection Multiple matching implementations are registered. Review profile expressions and bean conditions; use explicit selection where appropriate.
Profile activation fails from YAML Incorrect YAML indentation or an invalid activation property. Check YAML syntax and the Spring Boot version's configuration rules.

23. Best Practices for Environment-Specific Profiles

  • Keep shared properties in application.properties or application.yml.
  • Use clear, consistent profile names such as dev, test, staging, and prod.
  • Use environment variables or a secret manager for credentials and API keys.
  • Never commit production secrets to version control.
  • Avoid destructive schema-generation settings in production.
  • Use migrations for controlled production database schema changes.
  • Test each important profile and the beans that it activates.
  • Keep production logging useful while avoiding sensitive data in logs.
  • Document required environment variables and deployment-specific settings.
  • Review property precedence when configuration values appear incorrect.
  • Do not use profiles as a replacement for authorization, access control, or infrastructure security.
  • Use the configuration approach supported by the Spring Boot version used in the project.

24. Practical Exercise: Create a Multi-Environment Application

Goal: Configure a Spring Boot employee-management application to run in development, testing, and production environments.

Tasks

  1. Create application.properties for shared application settings.
  2. Create application-dev.properties with development logging and a local database.
  3. Create application-test.properties with an isolated test database.
  4. Create application-prod.properties with environment-provided database credentials.
  5. Activate each profile using the command line or environment variables.
  6. Create two implementations of a service interface and select them with @Profile.
  7. Write a Spring Boot test using @ActiveProfiles("dev").
  8. Verify that production secrets are not committed to the repository.

Expected Result

The same packaged application should run in different environments using the appropriate configuration. The selected profile should determine the relevant settings and profile-conditional beans without requiring separate application builds.

25. Interview Questions and Answers

Q1. What is a Spring profile?

A Spring profile is a mechanism for conditionally enabling configuration and beans for particular environments or application scenarios.

Q2. How do you create a profile-specific properties file?

Create a file using the naming convention application-{profile}.properties, such as application-dev.properties.

Q3. How can you activate a Spring Boot profile?

Use spring.profiles.active in non-profile-specific configuration, a command-line argument such as --spring.profiles.active=dev, or the SPRING_PROFILES_ACTIVE environment variable.

Q4. What is the purpose of the @Profile annotation?

It restricts the registration of a bean or configuration class to environments whose active profiles match the specified expression.

Q5. What is the difference between active and default profiles?

Active profiles are explicitly selected for the application. The default profile is used when no active profile has been specified, with the default name being default unless changed.

Q6. Can multiple profiles be active simultaneously?

Yes. Multiple profiles can be activated together, allowing the application to combine configuration and beans from more than one profile.

Q7. What are profile groups?

Profile groups allow one logical profile to activate a predefined set of other profiles, making related configurations easier to manage.

Q8. Should database passwords be stored in profile-specific files?

Real secrets should not be committed to source control. Use environment variables, a secret manager, or another approved secure configuration mechanism.

Q9. How do you test a particular profile?

Use Spring testing support such as @ActiveProfiles("test") or @ActiveProfiles("dev") to load the desired profile for a test context.

Q10. Do profiles replace application security?

No. Profiles select configuration and beans. Authentication, authorization, database permissions, network controls, and secret management must still be implemented independently.

26. Quick Revision Checklist

  • Understand why applications need different environment settings.
  • Know the application-{profile}.properties naming convention.
  • Know how to activate profiles from a command line and environment variable.
  • Understand how @Profile controls bean registration.
  • Know the difference between active and default profiles.
  • Understand profile expressions and profile groups.
  • Keep credentials outside source-controlled configuration files.
  • Test profile-specific settings and bean implementations.
  • Verify effective configuration when values are unexpectedly overridden.
  • Keep production database and logging configuration safe.

27. Conclusion

Environment-specific profiles are an important Spring Boot feature for building applications that can run consistently across development, testing, staging, and production. By combining shared configuration, profile-specific files, environment variables, and the @Profile annotation, developers can select suitable settings and beans without maintaining separate codebases.

Good profile management also requires secure secret handling, careful database configuration, automated testing, and awareness of configuration precedence. These practices make Spring Boot applications easier to deploy, troubleshoot, and maintain.

28. Additional Learning Resources

Previous Next
whatsapp