@Profile

Registers a component, @Bean or configuration class only when one of the named profiles, or a profile expression, is active.

Signature
@Profile("dev")  |  @Profile({"dev", "test"})  |  @Profile("prod & !eu")
  • Added in Spring Boot Spring Framework 3.1

Parameters

ParameterTypeDescription
$valueString[]Profile names or expressions. The bean is registered when any one of them matches. Expressions support !, & and |, with parentheses to mix & and |.

Return value

n/aMakes the annotated component, configuration class or @Bean method conditional on the active profiles.

Changelog

  • PHP Spring Framework 5.1Profile expressions with &, | and parentheses.

@Profile makes a bean conditional on the active profiles. A class or @Bean method marked @Profile("dev") is only registered when dev is active; otherwise Spring behaves as if it did not exist. Put it on a @Component, a @Configuration class (affecting all its beans) or a single @Bean method.

Activating profiles

Set spring.profiles.active: in a properties file, as the SPRING_PROFILES_ACTIVE environment variable, or as --spring.profiles.active=prod on the command line. In tests use @ActiveProfiles. When nothing is set, the default profile is active. Spring Boot also loads application-{profile}.properties for each active profile, so profiles drive both beans and settings.

Expressions

The value takes names or expressions. Several values mean "any of these": @Profile({"dev", "test"}). Expressions support !, & and |, for example @Profile("prod & !eu"). Mixing & and | needs parentheses, "(prod | staging) & eu", or the expression is rejected at startup.

Use profiles for environments, not features

Profiles answer "where is this running?": local, test, staging, production. They are a poor switch for a feature such as "send audit events", because every new environment then needs the right mix of profile names. Use @ConditionalOnProperty for a feature switch and set the property per environment.

Mistakes to avoid

  • @Profile("!prod") on a fake payment gateway also activates it in staging, in a new region you add later, and anywhere someone forgot to set a profile. Prefer a positive list, @Profile({"local", "test"}), for anything unsafe in production.
  • A real implementation with no profile next to a fake with @Profile("local"): in local both exist and injection is ambiguous. Give each a profile, or mark one @Primary.
  • Reading Environment.getActiveProfiles() inside business code to branch on environment. Put the difference into two beans instead and let the profile choose between them.

Startup logs the active profiles in the line "The following 1 profile is active". Check it first when a bean seems to be missing.

Example

Example · java
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

interface MailSender {
    void send(String to, String subject, String body);
}

// Real delivery only in the deployed environments.
@Component
@Profile({"staging", "prod"})
class SmtpMailSender implements MailSender {
    public void send(String to, String subject, String body) {
        // hand over to the SMTP server
    }
}

// On laptops and in tests, mail is only logged.
@Component
@Profile({"local", "test", "default"})
class LoggingMailSender implements MailSender {
    public void send(String to, String subject, String body) {
        System.out.println("Mail to " + to + ": " + subject);
    }
}

@Service
public class PasswordResetService {

    private final MailSender mail;

    public PasswordResetService(MailSender mail) {
        this.mail = mail;
    }

    public void sendLink(String email, String token) {
        mail.send(email, "Reset your password", "https://shop.example/reset?token=" + token);
    }
}

When to use it

  • Logging emails locally while sending real ones in staging and production
  • A demo environment with a frozen clock and seeded data
  • Keeping a fake payment gateway out of production by listing the profiles where it may run

Frequently asked questions

How do I activate a profile?

Set spring.profiles.active: as the SPRING_PROFILES_ACTIVE environment variable, a --spring.profiles.active command-line argument, or in a properties file. In tests, use @ActiveProfiles.

What profile is active when I set none?

The profile called default, unless spring.profiles.default names a different one. Beans with @Profile("default") are registered only while that built-in default profile is the one in effect: setting any active profile, or changing spring.profiles.default, switches them off.

More examples

Activating profiles and grouping them

spring.profiles.default replaces the built-in 'default' profile when no profile is active. A profile group lets one name switch on several narrower profiles, each with its own application-{profile}.properties.

Example · properties
# application.properties: the profile used when nothing else is set.
spring.profiles.default=local

# Activating prod also activates the groups listed for it.
spring.profiles.group.prod=postgres,json-logs

# In a deployment, prefer the environment variable instead:
#   SPRING_PROFILES_ACTIVE=prod

A whole configuration class for one environment

Every bean in the class depends on the expression. The '!prod' part is a safety net: even if someone activates demo and prod together by mistake, the frozen clock stays out of production.

Example · java
import java.time.Clock;
import java.time.Instant;
import java.time.ZoneOffset;

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

@Configuration(proxyBeanMethods = false)
@Profile("demo & !prod")
public class DemoConfig {

    // A frozen clock so the demo environment always shows the same dates.
    @Bean
    Clock clock() {
        return Clock.fixed(Instant.parse("2026-01-15T09:00:00Z"), ZoneOffset.UTC);
    }
}

Checking profile behaviour in a test

ApplicationContextRunner starts a tiny context in milliseconds, so the rule 'only in prod' is checked without booting the whole application.

Example · java
import static org.assertj.core.api.Assertions.assertThat;

import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Component;

@Component
@Profile("prod")
class RealSmsSender {
}

class ProfileTest {

    private final ApplicationContextRunner runner =
            new ApplicationContextRunner().withUserConfiguration(RealSmsSender.class);

    @Test
    void absentWithoutProfile() {
        runner.run(context -> assertThat(context).doesNotHaveBean(RealSmsSender.class));
    }

    @Test
    void presentInProd() {
        runner.withPropertyValues("spring.profiles.active=prod")
              .run(context -> assertThat(context).hasSingleBean(RealSmsSender.class));
    }
}

Discussion

  • Be the first to comment on this lesson.