Spring.profiles.active in Spring Boot: complete guide with examples

Spring.profiles.active in Spring Boot: complete guide with examples

spring.profiles.active is a Spring Boot property that tells the framework which configuration profile to load at startup. Set it once, and Spring automatically picks the right application-{profile}.yml, registers the right beans, and skips everything else. The result: one codebase, zero environment-specific hacks, clean deployments to dev, staging, and production.

Quick answer

  • What it does: spring.profiles.active tells Spring Boot which profile or profiles to activate at startup.
  • Best for local default: set it in application.properties or application.yml.
  • Best for Docker, Kubernetes, and CI/CD: use SPRING_PROFILES_ACTIVE.
  • Best for one-off runs: use --spring.profiles.active=... on the command line.
  • Most important rule: the highest-precedence property source wins.
  • Common mistake: putting spring.profiles.active inside a profile-specific document — that is invalid.

The most common place to set it is application.properties:

spring.profiles.active=development

Or activate it at runtime without touching any file:

java -jar myapp.jar --spring.profiles.active=production

Key Benefits at a Glance

  • Environment-Specific Configuration: Switch between dev, test, and prod settings without changing application code.
  • Improved Security: Keep production credentials isolated from development environments, reducing the risk of accidental data leaks.
  • Faster Development Cycles: Use lightweight in-memory databases locally; switch to real infrastructure only in production.
  • Streamlined CI/CD: Let pipelines inject profiles via environment variables — no file edits, no merge conflicts.
  • Easier Maintenance: One property change per environment instead of scattered conditional logic throughout your code.

Key takeaways

  • Set spring.profiles.active via config file, environment variable, command line, or code
  • Multiple profiles can be active simultaneously using comma-separated values
  • Profile-specific files automatically override the base config
  • The highest-precedence property source wins
  • Profile groups help simplify large multi-profile setups

Understanding Spring profiles: core concepts and benefits

A Spring profile is a named set of bean definitions and configuration properties that activates together. When you mark a bean or configuration class with @Profile("production"), Spring only registers it when that profile is active. Everything else is ignored.

@Configuration
@Profile("development")
public class DevMailConfig {
    @Bean
    public JavaMailSender mailSender() {
        // Points to a local MailHog instance, never sends real email
        ...
    }
}
  • Profile names are arbitrary identifiers that should stay clean and descriptive
  • Multiple profiles can be active at once
  • Profiles work at both the bean level (@Profile) and the config file level (application-{profile}.yml)
  • The default profile activates automatically when nothing else is set

By default, Spring Boot validates profile names. Current documentation allows profile names to contain letters, numbers, and these characters: -, _, ., +, and @. A profile name must start and end with a letter or number. This is stricter than “any arbitrary string”, and it helps avoid parsing problems.

  • Good examples: dev, production, feature-x, redis_cache, prod.eu
  • Avoid spaces and messy naming conventions
  • If you really need looser rules, Spring Boot supports spring.profiles.validate=false

The practical payoff is obvious: a developer can run the app locally with lightweight infrastructure, while the production container injects hardened configuration through the active profile. Same jar, completely different runtime behavior.

The spring.profiles.active property: detailed explanation

The spring.profiles.active property accepts a comma-separated list of profile names. Spring resolves it early in the startup sequence, before bean registration begins, so profile-based bean loading, configuration file selection, and auto-configuration all happen with the final active profile list already known.

“You can use a spring.profiles.active Environment property to specify which profiles are active.”
Spring Boot Documentation
Source link
  1. Spring resolves spring.profiles.active from all available property sources
  2. The highest-precedence source wins
  3. Profile-specific config files are loaded and merged over the base config
  4. Beans annotated with @Profile are registered or skipped accordingly
  5. Auto-configuration adapts to the active profiles

Important restriction

  • spring.profiles.active can only be defined in a non-profile-specific document.
  • The same rule also applies to spring.profiles.default, spring.profiles.include, and spring.profiles.group.
  • Do not place these inside application-production.yml or inside YAML sections activated by spring.config.activate.on-profile.
  • If you do, the configuration is invalid and Spring Boot will not treat it as a proper profile activation setup.
# ✅ valid: non-profile-specific document
spring:
  profiles:
    active: production

---
# ❌ invalid: profile-specific document must not set spring.profiles.active
spring:
  config:
    activate:
      on-profile: production
  profiles:
    active: metrics
ValueResult
spring.profiles.active=devActivates the dev profile
spring.profiles.active=dev,h2Activates both dev and h2
spring.profiles.active=production,redisActivates production and redis
(not set)Activates the default profile

Methods for setting active profiles

Spring supports several ways to activate profiles. Each has its own place depending on whether you are running locally, inside a container, or through a CI/CD pipeline.

MethodPrecedenceBest forPortability
Command LineHighestDev / quick testingLow
Environment VariablesHighDocker / Kubernetes / CIHigh
System PropertiesMediumApp servers / controlled JVM startupMedium
Configuration FilesLowestDefaults / fallbackHigh

Where to set spring.profiles.active in real projects

EnvironmentRecommended approachWhy
Local developmentapplication.properties or IDE run configSimple, predictable default for every developer
CI/CD pipelineEnvironment variableNo code changes, easy injection per stage
Docker / KubernetesSPRING_PROFILES_ACTIVEMatches container-native config patterns
One-off debuggingCommand-line argumentHighest precedence, easiest temporary override

Command line activation

The command line gives you the highest precedence and zero file changes. Two syntaxes work:

# JVM system property
java -Dspring.profiles.active=dev,hsqldb -jar myapplication.jar

# Spring Boot argument style
java -jar myapplication.jar --spring.profiles.active=production,mysql

Both are equivalent in effect. The Spring Boot argument style is slightly more natural in Boot-only applications, and it works especially well for one-off debugging and local testing.

Environment variables and system properties

The environment variable SPRING_PROFILES_ACTIVE is the standard way to inject profiles in containers and CI pipelines. Spring Boot maps it automatically through relaxed binding.

# Unix/Linux/macOS
export SPRING_PROFILES_ACTIVE=production,redis
java -jar myapplication.jar

# Windows Command Prompt
set SPRING_PROFILES_ACTIVE=production,redis
java -jar myapplication.jar

# Windows PowerShell
$env:SPRING_PROFILES_ACTIVE="production,redis"
java -jar myapplication.jar

In Docker Compose, pass it directly in the service definition:

services:
  app:
    image: myapp:latest
    environment:
      - SPRING_PROFILES_ACTIVE=production,redis
    ports:
      - "8080:8080"

In Kubernetes, inject it in the pod spec:

env:
  - name: SPRING_PROFILES_ACTIVE
    value: "production,redis"

System properties are an alternative when environment variables are restricted:

System.setProperty("spring.profiles.active", "development,h2");

Programmatic activation

For cases where the profile depends on runtime logic, activate it before the application context starts:

@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication app = new SpringApplication(Application.class);
        app.setAdditionalProfiles(determineActiveProfile());
        app.run(args);
    }

    private static String determineActiveProfile() {
        return System.getProperty("deployment.environment", "development");
    }
}

setAdditionalProfiles() adds profiles to the application before startup rather than replacing every other possible source. Use it when your application needs to activate supporting profiles programmatically, not when you want to override external configuration supplied by operations or CI/CD.

For tests, prefer @ActiveProfiles instead of setting system properties manually. It is cleaner and resets automatically with the test context.

Configuration file approaches

Setting the profile in a config file provides a reliable default. This is ideal for establishing a safe local-development baseline so the app starts without any external arguments.

FormatReadabilityComplex structuresRecommended for
PropertiesGoodLimitedSimple configs, legacy projects
YAMLExcellentExcellentMost Spring Boot projects
# application.properties
spring.profiles.active=development
# application.yml
spring:
  profiles:
    active: development

Keep this value set to your safe local profile in version control. Override it via environment variable or command line in automated environments.

Profile activation priority

When the same property is set in multiple places, Spring applies a strict precedence order. The highest-precedence source wins completely.

  1. Command line arguments (--spring.profiles.active or -Dspring.profiles.active)
  2. Environment variables (SPRING_PROFILES_ACTIVE)
  3. System properties set programmatically (System.setProperty(...))
  4. Configuration files (application.properties / application.yml)
  5. Default profile — activates automatically if nothing else is set
  • spring.profiles.active is not merged across property sources — the highest-precedence value wins.
  • If you need to add profiles on top of the active ones instead of replacing them, use spring.profiles.include.

A common debugging trap is seeing an unexpected profile even though the properties file says something else. In practice, that usually means an environment variable or CLI argument already overrode it.

  • If SPRING_PROFILES_ACTIVE=production is set in the environment and spring.profiles.active=dev is in application.properties, production wins.
  • Command-line arguments override even environment variables — useful for simulating production-like scenarios locally.

Using spring.profiles.include

Sometimes you do not want to replace the active profile list — you want to add profiles on top of it. That is what spring.profiles.include is for.

spring:
  profiles:
    include:
      - common
      - local

With this setup, common and local are added before the explicitly active profiles. This is useful for shared infrastructure profiles such as common logging, shared metrics, or local development support.

  • Use spring.profiles.active when you want to choose profiles explicitly
  • Use spring.profiles.include when you want to add supporting profiles automatically

Profile-specific configuration files

Spring Boot automatically loads application-{profile}.properties or application-{profile}.yml when a profile is active. Profile-specific files are loaded after the base config and override matching keys.

src/main/resources/
├── application.yml
├── application-development.yml
├── application-testing.yml
├── application-staging.yml
└── application-production.yml
  • The base file always loads first
  • The profile-specific file loads second and overrides matching keys
  • Properties not present in the profile-specific file fall back to the base file
  • With multiple active profiles, later files win conflicts

Keep the base file lean. Only properties that are truly identical across all environments belong there.

Multi-document YAML files

Instead of multiple files, you can consolidate profile-specific configuration into a single application.yml using YAML document separators.

ApproachProsCons
Separate filesClear separation, easy review per environmentMore files to manage
Multi-document YAMLSingle file, side-by-side comparisonGets messy when profiles multiply
# Applies to all profiles
server:
  port: 8080
logging:
  level:
    root: INFO

---
spring:
  config:
    activate:
      on-profile: development
datasource:
  url: jdbc:h2:mem:devdb
  username: dev
  password: dev
logging:
  level:
    com.example: DEBUG

---
spring:
  config:
    activate:
      on-profile: production
datasource:
  url: jdbc:mysql://prod-db:3306/proddb
  username: ${DB_USERNAME}
  password: ${DB_PASSWORD}
logging:
  level:
    com.example: WARN

In Spring Boot 2.4+, use spring.config.activate.on-profile for YAML document activation. It is the modern and recommended form.

Real-world implementation examples

The most common real-world profile scenarios are database configuration, feature toggles, and logging behavior.

Database configuration:

@Configuration
@Profile("development")
public class DevelopmentDatabaseConfig {

    @Bean
    @Primary
    public DataSource dataSource() {
        return new EmbeddedDatabaseBuilder()
            .setType(EmbeddedDatabaseType.H2)
            .addScript("schema.sql")
            .addScript("test-data.sql")
            .build();
    }
}

@Configuration
@Profile("production")
public class ProductionDatabaseConfig {

    @Bean
    @Primary
    public DataSource dataSource() {
        HikariConfig config = new HikariConfig();
        config.setJdbcUrl("jdbc:mysql://prod-db:3306/proddb");
        config.setUsername("${DB_USERNAME}");
        config.setPassword("${DB_PASSWORD}");
        config.setMaximumPoolSize(20);
        return new HikariDataSource(config);
    }
}

Feature toggles:

@Controller
@Profile("feature-new-ui")
public class NewDashboardController {

    @GetMapping("/dashboard")
    public String newDashboard(Model model) {
        return "new-dashboard";
    }
}

@Controller
@Profile("!feature-new-ui")
public class LegacyDashboardController {

    @GetMapping("/dashboard")
    public String legacyDashboard(Model model) {
        return "legacy-dashboard";
    }
}

Logging:

# application-development.yml
logging:
  level:
    com.example: DEBUG
    org.springframework.web: DEBUG

# application-production.yml
logging:
  level:
    com.example: WARN
    root: ERROR

Profile-aware HTTP responses follow the same idea: detailed diagnostics in development, safer output in production. See ResponseEntity in Spring Boot. When structuring data between layers, DTOs keep your API contracts clean across all profiles — see What is DTO in Spring Boot.

Default profile and its purpose

The default profile is a safety net. Spring activates it automatically when no other profiles are set.

@Configuration
@Profile("default")
public class DefaultConfiguration {

    @Bean
    public DataSource dataSource() {
        return new EmbeddedDatabaseBuilder()
            .setType(EmbeddedDatabaseType.H2)
            .build();
    }

    @Bean
    public CacheManager cacheManager() {
        return new ConcurrentMapCacheManager();
    }
}

You can also rename the default profile using spring.profiles.default:

spring.profiles.default=local-development

In practice, the default profile should represent “what a developer gets on first clone” — safe local dependencies, no production secrets, no real external side effects.

Spring Boot profile integration

Spring Boot adds a few important features on top of base Spring profile support, especially for configuration files and deployment workflows.

FeatureTraditional SpringSpring Boot
YAML multi-documentBasicFull support with on-profile
Profile groupsNot availableBuilt-in
Maven / Gradle integrationManualSimple to wire
Auto-configuration awarenessManualProfile-aware out of the box
Actuator visibilityNot built in/actuator/env helps inspect config

Maven integration:

<profiles>
    <profile>
        <id>development</id>
        <properties>
            <spring.profiles.active>dev,h2</spring.profiles.active>
        </properties>
    </profile>
    <profile>
        <id>production</id>
        <properties>
            <spring.profiles.active>prod,mysql</spring.profiles.active>
        </properties>
    </profile>
</profiles>

Gradle integration:

bootRun {
    args = ["--spring.profiles.active=${project.findProperty('profile') ?: 'development'}"]
}
// Run with: ./gradlew bootRun -Pprofile=production

Profile groups in Spring Boot

Profile groups let you activate multiple profiles with one logical name. This is cleaner than forcing operators to remember long comma-separated lists.

spring:
  profiles:
    group:
      production: "proddb,prodcache,prodlogging"
      development: "devdb,devcache,devlogging,debug"
      testing: "testdb,testcache,mockedservices"

Groups can also be composed for larger setups:

spring:
  profiles:
    group:
      database-dev: "h2,flyway"
      database-prod: "mysql,flyway"
      cache-dev: "simple-cache"
      cache-prod: "redis,redis-cluster"

      full-dev: "database-dev,cache-dev,debug"
      full-prod: "database-prod,cache-prod,monitoring"

Profile groups are especially useful when environments activate multiple infrastructure capabilities together and you want a single, memorable top-level profile such as production.

Best practices and common pitfalls

  • Use descriptive names instead of ambiguous shortcuts when it improves clarity
  • Keep profile-specific files minimal — only override what really differs
  • Never commit real production credentials, even in production files
  • Use placeholders like ${DB_PASSWORD} for secrets
  • Document which profiles are expected in each environment
PitfallSymptomFix
Profile not activatingDefault config used, unexpected beansCheck precedence — another property source may be overriding it
Wrong config loadedApp connects to wrong databaseVerify file naming: application-dev.yml, not application_dev.yml
Multiple profiles conflictBean creation errors or ambiguityReview @Profile usage and add @Primary where appropriate
Profile typoSilent fallback to default behaviorInspect active profiles via logs or Actuator
Production profile in devLocal machine hits real DB or sends real emailsCommit a safe local default and override only in deployment

Debugging and troubleshooting profile issues

  1. Enable debug logging for Spring environment processing
  2. Check active profiles via Environment.getActiveProfiles()
  3. Review startup logs for config loading order
  4. Test each profile in isolation before combining them
  5. Use Actuator to inspect the final resolved configuration

Enable useful debug logging:

logging.level.org.springframework.core.env=DEBUG
logging.level.org.springframework.boot.context.config=DEBUG

Verify active profiles programmatically:

@Component
public class ProfileVerificationComponent {

    @Autowired
    private Environment environment;

    @PostConstruct
    public void verifyProfiles() {
        log.info("Active profiles: {}", Arrays.toString(environment.getActiveProfiles()));
        log.info("Default profiles: {}", Arrays.toString(environment.getDefaultProfiles()));
    }
}

In non-production environments, the Actuator /actuator/env endpoint is one of the best tools for debugging why a profile or property value resolved the way it did.

management:
  endpoints:
    web:
      exposure:
        include: env,health,info

Advanced profile techniques

The @Profile annotation supports boolean expressions using & (AND), | (OR), and ! (NOT). This lets you describe precise activation rules without inventing too many profile names.

@Configuration
@Profile("production & !debug & (mysql | postgresql)")
public class ProductionDatabaseConfig {
    ...
}

@Component
@Profile("!test")
public class ExternalNotificationService {
    ...
}

For custom auto-configuration libraries, combine @ConditionalOnProperty with @Profile when both environment and capability checks matter:

@Configuration
@Profile("metrics")
@ConditionalOnClass(PrometheusMeterRegistry.class)
public class MetricsAutoConfiguration {

    @Bean
    @ConditionalOnMissingBean
    public MeterRegistry meterRegistry() {
        return new PrometheusMeterRegistry(PrometheusConfig.DEFAULT);
    }
}

Do not try to switch profiles dynamically after the application context is already running. If you need dynamic behavior at runtime, use feature flags or @ConditionalOnProperty within a stable profile setup instead.

Why this matters beyond one property: developers who understand spring.profiles.active usually design cleaner deployment pipelines, safer secrets handling, better local-dev setups, and more reliable production releases. In real Spring Boot work, profiles are part of a bigger skill set: configuration architecture, environment isolation, observability, and deployment discipline.

More Spring Boot guides

Frequently Asked Questions

spring.profiles.active is a Spring Boot property that specifies which profiles are active for the current application run. When set, Spring loads the matching configuration files and registers only the beans that match those profiles.

Use either java -jar app.jar --spring.profiles.active=production or java -Dspring.profiles.active=production -jar app.jar. Both work, and command-line values have the highest precedence.

spring.profiles.active explicitly sets which profiles are active. spring.profiles.default defines which profile activates only when nothing else is active.

Yes. Use a comma-separated list such as spring.profiles.active=production,redis,monitoring. All listed profiles become active together.

Use the environment variable SPRING_PROFILES_ACTIVE. Spring Boot automatically maps it to spring.profiles.active.

Create files such as application-dev.yml or application-production.yml. Spring Boot loads the base file first, then overlays the profile-specific file for the active profile.

No. spring.profiles.active must be defined only in non-profile-specific documents. It cannot be placed in profile-specific files or YAML sections activated with spring.config.activate.on-profile.

spring.profiles.active explicitly selects which profiles are active. spring.profiles.include adds extra profiles on top of the active ones. Use active to choose, and include to supplement.