Profiles & Environments
Reviewed & published by Brayan K
Profiles let one build behave differently per environment. Tag beans with @Profile, layer application-<profile>.properties, and flip everything with spring.profiles.active.
Part of the free Java course at LearnCodingFast — hands-on lessons with worked examples and the output they print, plus practice exercises and a quick quiz.
Before You Start
You should understand configuration and properties and how dependency injection picks beans. Profiles build directly on both.
What You'll Learn
- What a profile is and why it helps
- Restricting beans with @Profile
- Per-profile property files
- Selecting profiles with spring.profiles.active
- Activating profiles via env var or CLI
- Swapping implementations per environment
The Big Idea — One Stage, Different Scenery
💡 Analogy: Think of your app as a theater stage and profiles as scene sets. The same actors (your code) perform on one stage, but a stagehand rolls in the "dev" scenery (a cardboard prop mailer, bright debug lights) or the "prod" scenery (the real backdrop, dimmed lights) depending on the show. spring.profiles.active is the cue that tells the stagehand which set to use; @Profile labels which props belong to which scene.
Build the play once; change the scenery per performance.
1️⃣ Per-Profile Property Files
application.properties is the base; application-dev.properties and application-prod.properties layer overrides on top when their profile is active. Activate one with spring.profiles.active.
# application.properties (base config, always loaded)
app.name=Bookstore
app.mailer=real
# application-dev.properties (overrides when the "dev" profile is active)
app.mailer=fake
logging.level.root=DEBUG
# application-prod.properties (overrides when the "prod" profile is active)
app.mailer=real
logging.level.root=WARN
# Activate a profile (any ONE of these):
# spring.profiles.active=dev (in application.properties)
# --spring.profiles.active=prod (command-line argument)
# SPRING_PROFILES_ACTIVE=prod (environment variable)2️⃣ Swapping Beans with @Profile
Annotate competing implementations with @Profile. A service depends on the interface; Spring injects whichever bean matches the active profile — no environment if/else in your logic.
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Component;
// A single interface, two implementations chosen by the ACTIVE profile.
public interface Mailer {
String send(String to, String body);
}
@Component
@Profile("dev") // created ONLY when "dev" is active
class FakeMailer implements Mailer {
public String send(String to, String body) {
return "DEV (not really sent) -> " + to;
}
}
@Component
@Profile("prod") // created ONLY when "prod" is active
class SmtpMailer implements Mailer {
public String send(String to, String body) {
return "SENT via SMTP -> " + to;
}
}
// A service just depends on the interface; Spring injects whichever
// implementation matches the active profile — no if/else in your code.import org.springframework.context.annotation.*;
// You can also group bean definitions per profile in a @Configuration class.
@Configuration
public class DataSourceConfig {
@Bean
@Profile("dev")
public String devDb() { // pretend this is a DataSource
return "in-memory H2 database";
}
@Bean
@Profile("prod")
public String prodDb() {
return "managed Postgres cluster";
}
}3️⃣ How Selection Works
Under the hood, Spring just picks the bean whose profile matches spring.profiles.active. Here is that selection logic in plain, runnable Java.
import java.util.*;
// PLAIN-JAVA illustration of "pick the bean for the ACTIVE profile",
// which is what @Profile + spring.profiles.active do for you.
public class Main {
interface Mailer { String send(String to); }
static class FakeMailer implements Mailer {
public String send(String to) { return "DEV (not really sent) -> " + to; }
}
static class SmtpMailer implements Mailer {
public String send(String to) { return "SENT via SMTP -> " + to; }
}
// choose the implementation based on the active profile
static Mailer mailerFor(String activeProfile) {
return switch (activeProfile) {
case "prod" -> new SmtpMailer();
default -> new FakeMailer(); // dev / default
};
}
public static void main(String[] args) {
// pretend spring.profiles.active was read from config:
String active = "dev";
Mailer mailer = mailerFor(active);
System.out.println("active profile: " + active);
System.out.println(mailer.send("ana@site.com"));
active = "prod";
System.out.println("active profile: " + active);
System.out.println(mailerFor(active).send("ben@site.com"));
}
}🧠 Quick Recall
Predict before you peek.
Answer: spring.profiles.active=prod (settable via file, CLI arg, or env var).
Answer: application-dev.properties, layered on top of the base file.
Answer: the default profile — base config and any non-profiled beans.
🎯 YOUR TURN — Sandbox vs live gateway
Provide two PaymentGateway implementations chosen by @Profile("dev") and @Profile("prod").
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Component;
// YOUR TURN: provide two implementations of a PaymentGateway.
// - interface PaymentGateway { String charge(int cents); }
// - @Profile("dev") -> SandboxGateway returns "SANDBOX charge " + cents
// - @Profile("prod") -> LiveGateway returns "LIVE charge " + cents
// - a @Component on each so Spring picks by active profile
//
// Then set spring.profiles.active=dev to use the sandbox locally.🧩 MINI-CHALLENGE — Layered property files
Design base and per-profile property files, then activate prod with an environment variable.
# MINI-CHALLENGE: design per-profile property files.
#
# Base (application.properties):
# app.rate-limit=100
# app.cache-enabled=true
#
# Provide overrides:
# application-dev.properties -> app.rate-limit=1000, app.cache-enabled=false
# application-prod.properties -> app.rate-limit=100, logging.level.root=WARN
#
# Then activate prod with an ENVIRONMENT VARIABLE (no file edit):
# SPRING_PROFILES_ACTIVE=prod
#
# Think: which keys come from the base file vs the profile file when prod is active?Common Errors
- ❌ Misspelling the property. spring.profile.active won't work. Fix: it is spring.profiles.active (plural).
- ❌ No bean for the active profile. Injection fails. Fix: ensure exactly one matching @Profile bean exists.
- ❌ Expecting the profile file to fully replace the base. It only overrides keys it defines. Fix: keep shared keys in the base file.
- ❌ Forgetting to set a profile in prod. Default config runs. Fix: set SPRING_PROFILES_ACTIVE in the environment.
- ❌ Two beans for the same active profile. Ambiguous injection. Fix: use distinct profiles or a @Primary.
- ❌ Putting secrets in profile files. Leak risk. Fix: inject secrets via env vars, not committed files.
Pro Tips
- 💡 Activate profiles via env vars so the same artifact runs anywhere.
- 💡 Keep the default (no-profile) behavior safe and require an explicit profile for special environments.
- 💡 Depend on interfaces and let @Profile pick the implementation — keep environment checks out of your code.
- 💡 You can activate multiple profiles (comma-separated) to compose configuration.
📋 Quick Reference
| Element | Purpose | Note |
|---|---|---|
| profile | named environment | dev/test/prod |
| @Profile("dev") | restrict a bean | Created if active |
| spring.profiles.active | select profile(s) | Comma-separated |
| application-dev.properties | per-profile config | Overrides base |
| default profile | no profile active | Base + non-profiled |
| env var | SPRING_PROFILES_ACTIVE | Activate at launch |
| CLI arg | --spring.profiles.active | Per run |
| @Bean + @Profile | profiled @Bean method | In @Configuration |
| multiple active | dev,metrics | Compose configs |
📚 Resources / Keep Learning
- 📘 Spring Boot — profiles (docs.spring.io)
- 📗 Spring Framework — bean definition profiles (docs.spring.io)
- 📗 Spring Boot — externalized configuration (docs.spring.io)
🎉 Lesson Complete!
You can now define profiles, restrict beans and @Bean methods with @Profile, layer application-<profile>.properties over the base, and select the active environment with spring.profiles.active via files, CLI args, or environment variables.
Practice quiz
What does a Spring profile represent?
- A user account
- A named set of beans and config active in a given environment
- A database index
- A logging level only
Answer: A named set of beans and config active in a given environment. A profile is a named grouping of beans and configuration activated for a particular environment (dev, test, prod).
What does @Profile("dev") on a bean mean?
- The bean is always created
- The bean is deleted in dev
- The bean is created only when the dev profile is active
- The bean runs twice
Answer: The bean is created only when the dev profile is active. @Profile("dev") makes the bean eligible for creation only when the dev profile is active.
Which property selects the active profile(s)?
- spring.active.profile
- spring.profiles.active
- profile.spring.use
- server.profile
Answer: spring.profiles.active. spring.profiles.active lists the profile(s) Spring should activate.
What file naming convention provides per-profile properties?
- application-<profile>.properties
- profile.<name>.properties
- <profile>.application.properties
- app.<profile>.yml only
Answer: application-<profile>.properties. application-dev.properties (etc.) supplies profile-specific overrides loaded on top of application.properties.
If no profile is explicitly active, what runs?
- Nothing
- Every profile at once
- Only prod
- The default profile / non-profiled beans and base config
Answer: The default profile / non-profiled beans and base config. With no active profile, Spring uses the default profile: base config and beans not restricted to a profile.
Can more than one profile be active at the same time?
- No, only one
- Yes, you can activate multiple profiles together
- Only two maximum
- Only in tests
Answer: Yes, you can activate multiple profiles together. spring.profiles.active accepts a comma-separated list, so several profiles can be active together.
How can you activate a profile at launch without editing files?
- You cannot
- Set spring.profiles.active via an env var or --spring.profiles.active arg
- Rebuild the JAR
- Rename the main class
Answer: Set spring.profiles.active via an env var or --spring.profiles.active arg. An environment variable or command-line argument can set spring.profiles.active at startup.
A good use of @Profile is to...
- Provide a fake email sender in dev and a real one in prod
- Define the primary key
- Replace validation
- Speed up the JVM
Answer: Provide a fake email sender in dev and a real one in prod. Profiles let you swap implementations per environment, e.g. a no-op/fake sender in dev versus a real one in prod.
Which is true about per-profile property files?
- They replace application.properties entirely
- They override matching keys on top of the base application.properties
- They are ignored
- They must be YAML
Answer: They override matching keys on top of the base application.properties. Profile-specific files override only the keys they define, layered on top of the base properties.
Where can @Profile be applied besides a @Component bean?
- Only on fields
- On a @Bean method or a whole @Configuration class
- Only on the main method
- Nowhere else
Answer: On a @Bean method or a whole @Configuration class. @Profile can also restrict individual @Bean methods or an entire @Configuration class to an active profile.
Continue this course
- Previous: Configuration & Properties
- Next: Spring Security Basics — SecurityFilterChain, authentication vs authorization and BCrypt
- Quick reference: Java cheat sheet
Frequently asked questions
What is a Spring profile?
A profile is a named environment — like dev, test, or prod — that activates a particular set of beans and configuration. By tagging beans with @Profile and providing profile-specific property files, you can make one build behave differently depending on which profile is active. This lets you, for example, use an in-memory database and verbose logging in development while using a managed database and minimal logging in production, all without changing or rebuilding the code.
How do I activate a profile?
Set the spring.profiles.active property. You can put spring.profiles.active=dev in application.properties, pass --spring.profiles.active=prod as a command-line argument, or set the SPRING_PROFILES_ACTIVE environment variable. The command-line and environment options are preferred for real deployments because they let the same artifact run in any environment without editing files — a container, for instance, just sets the environment variable. You can also list several profiles, comma-separated, to activate them together.
What does @Profile do on a bean or configuration?
@Profile("dev") restricts a bean (or an entire @Configuration class, or a @Bean method) so it is only created when that profile is active. This is the mechanism for swapping implementations per environment: you can have a FakeMailer annotated @Profile("dev") and an SmtpMailer annotated @Profile("prod"), both implementing the same interface. A service simply depends on the interface, and Spring injects whichever implementation matches the active profile — no environment checks scattered through your business logic.
How do profile-specific property files work?
Spring Boot loads application.properties as the base, then layers application-<profile>.properties on top for each active profile. So application-dev.properties only needs to specify the keys that differ from the base; those override the matching base keys, while everything else falls through to application.properties. The same applies to YAML with application-<profile>.yml. This layering keeps shared configuration in one place and isolates the per-environment differences.
What happens if no profile is active?
Spring uses the default profile. That means beans not annotated with any @Profile are created normally, and only the base application.properties (and any properties for a configured default profile) apply; profile-specific files like application-dev.properties are not loaded. It is good practice to make the no-profile, default behavior safe and conservative, and to require an explicit profile for environments that need special configuration, so nothing accidentally runs with the wrong settings.