Week 2 Day 3 — Spring Profiles: dev, test, prod, and @Profile
Goal
Today I want to understand Spring profiles.
Main questions:
- What is a Spring profile?
- Why do we need profiles?
- How do
application-dev.yml,application-test.yml, andapplication-prod.ymlwork? - How do I activate a profile?
- What does
@Profiledo? - Can I have multiple active profiles?
- What does
@Profile("!prod")mean? - How do profiles affect beans?
- How do profiles affect configuration files?
- What are common exam traps?
1. Quick Review from Day 2
In Day 2, I learned:
- External configuration keeps environment-specific values outside Java code.
- Spring Boot reads configuration from
application.properties,application.yml, environment variables, command-line arguments, and more. @Valueinjects one value.@ConfigurationPropertiesbinds grouped configuration.- Environment variables can override file configuration.
- Secrets should not be committed to Git.
Memory sentence:
@Value is for one value.
@ConfigurationProperties is for grouped config.
Today I learn how to use different configuration for different environments.
2. What Is a Spring Profile?
A Spring profile is a way to activate different configuration or beans for different environments.
Common profiles:
dev
test
prod
local
docker
ci
staging
Simple definition:
A Spring profile is a named environment mode that controls which configuration and beans are active.
Example:
dev = local development
test = automated tests
prod = production
3. Why Do We Need Profiles?
Different environments need different settings.
Example:
Local development
spring:
datasource:
url: jdbc:postgresql://localhost:5432/app_dev
Production
spring:
datasource:
url: jdbc:postgresql://prod-db:5432/app_prod
Same code.
Different configuration.
This is exactly what profiles help with.
4. Real Example
Imagine a Spring Boot app with email sending.
In development, I do not want to send real emails.
In production, I want real emails.
So I can have:
dev profile -> FakeEmailSender
prod profile -> RealEmailSender
Example:
public interface EmailSender {
void send(String to, String message);
}
@Service
@Profile("dev")
public class FakeEmailSender implements EmailSender {
@Override
public void send(String to, String message) {
System.out.println("Fake email to " + to);
}
}
@Service
@Profile("prod")
public class RealEmailSender implements EmailSender {
@Override
public void send(String to, String message) {
// send real email
}
}
If dev is active, Spring creates FakeEmailSender.
If prod is active, Spring creates RealEmailSender.
5. Profile-Specific Config Files
Spring Boot supports profile-specific configuration files.
Common files:
application.yml
application-dev.yml
application-test.yml
application-prod.yml
Base file:
## application.yml
spring:
application:
name: klarsync
server:
port: 8080
Development file:
## application-dev.yml
spring:
datasource:
url: jdbc:postgresql://localhost:5432/klarsync_dev
username: postgres
password: postgres
logging:
level:
org.springframework: INFO
Production file:
## application-prod.yml
spring:
datasource:
url: jdbc:postgresql://prod-db:5432/klarsync
username: ${DB_USERNAME}
password: ${DB_PASSWORD}
logging:
level:
org.springframework: WARN
6. How Spring Loads Profile Config
If no profile is active, Spring loads:
application.yml
If dev profile is active, Spring loads:
application.yml
application-dev.yml
If prod profile is active, Spring loads:
application.yml
application-prod.yml
Profile-specific values can override base values.
Memory sentence:
application.ymlis base config.application-dev.ymloverrides it whendevis active.
7. Example: Override Values
Base file:
## application.yml
server:
port: 8080
app:
name: klarsync
email-enabled: true
Dev file:
## application-dev.yml
server:
port: 8081
app:
email-enabled: false
If dev is active:
server.port = 8081
app.name = klarsync
app.email-enabled = false
server.port is overridden.
app.email-enabled is overridden.
app.name remains from the base file.
8. How to Activate a Profile
There are several ways.
Option 1 — In application.yml
spring:
profiles:
active: dev
This works, but it is not always recommended for production because profile selection should often come from the environment.
Option 2 — Command Line
java -jar app.jar --spring.profiles.active=prod
Option 3 — Environment Variable
SPRING_PROFILES_ACTIVE=prod java -jar app.jar
This is common in Docker and production.
Option 4 — IDE Run Configuration
In IntelliJ, I can add:
-Dspring.profiles.active=dev
or environment variable:
SPRING_PROFILES_ACTIVE=dev
Option 5 — Test Annotation
In tests:
@SpringBootTest
@ActiveProfiles("test")
class TaskServiceTest {
}
This activates the test profile for the test.
9. Best Practice for Profile Activation
For local development, using dev in IDE is fine.
For production, prefer environment variables or deployment config.
Good:
SPRING_PROFILES_ACTIVE=prod
Avoid committing production profile activation into Git:
spring:
profiles:
active: prod
Why?
Because it can accidentally make local or test environments use production configuration.
10. @Profile
@Profile controls whether a bean is created for a specific profile.
Example:
@Service
@Profile("dev")
public class FakeEmailSender implements EmailSender {
}
This bean is only created when the dev profile is active.
Example:
@Service
@Profile("prod")
public class RealEmailSender implements EmailSender {
}
This bean is only created when the prod profile is active.
11. @Profile on @Bean Methods
@Profile can also be used on @Bean methods.
@Configuration
public class EmailConfig {
@Bean
@Profile("dev")
public EmailSender fakeEmailSender() {
return new FakeEmailSender();
}
@Bean
@Profile("prod")
public EmailSender realEmailSender() {
return new RealEmailSender();
}
}
If dev is active, Spring creates fakeEmailSender.
If prod is active, Spring creates realEmailSender.
12. @Profile on Configuration Classes
You can put @Profile on a whole configuration class.
@Configuration
@Profile("dev")
public class DevConfig {
@Bean
public DataInitializer dataInitializer() {
return new DataInitializer();
}
}
This whole configuration class is active only in dev.
If dev is not active, Spring ignores this configuration class and its beans.
13. Multiple Profiles
Spring can have multiple active profiles.
Example:
java -jar app.jar --spring.profiles.active=dev,docker
Active profiles:
dev
docker
Spring then loads:
application.yml
application-dev.yml
application-docker.yml
Beans with either profile may become active.
Example:
@Profile("dev")
active if dev is active.
@Profile("docker")
active if docker is active.
14. Profile Expressions
@Profile supports simple expressions.
Not profile
@Profile("!prod")
Meaning:
Active when prod is NOT active.
Example:
@Service
@Profile("!prod")
public class ConsoleEmailSender implements EmailSender {
}
This bean is active in dev, test, or other non-prod environments.
AND expression
@Profile("dev & docker")
Meaning:
Active only when both dev and docker are active.
OR expression
@Profile("dev | test")
Meaning:
Active when dev or test is active.
15. Common Profile Expressions
| Expression | Meaning | |
|---|---|---|
dev | active when dev is active | |
prod | active when prod is active | |
!prod | active when prod is not active | |
| `dev | test` | active when dev or test is active |
dev & docker | active when both dev and docker are active |
16. Real Example: Dev vs Prod Email
Interface:
public interface EmailSender {
void send(String to, String message);
}
Dev implementation:
@Service
@Profile("dev")
public class ConsoleEmailSender implements EmailSender {
@Override
public void send(String to, String message) {
System.out.println("DEV email to " + to + ": " + message);
}
}
Prod implementation:
@Service
@Profile("prod")
public class SmtpEmailSender implements EmailSender {
@Override
public void send(String to, String message) {
// send via SMTP provider
}
}
Service:
@Service
public class RegistrationService {
private final EmailSender emailSender;
public RegistrationService(EmailSender emailSender) {
this.emailSender = emailSender;
}
}
If dev is active:
ConsoleEmailSender is injected.
If prod is active:
SmtpEmailSender is injected.
17. What Happens If No Profile Matches?
Example:
@Service
@Profile("dev")
public class ConsoleEmailSender implements EmailSender {
}
@Service
@Profile("prod")
public class SmtpEmailSender implements EmailSender {
}
Service:
@Service
public class RegistrationService {
public RegistrationService(EmailSender emailSender) {
}
}
If no profile is active:
No EmailSender bean exists.
Application fails to start.
Typical error:
No qualifying bean of type 'EmailSender' available
Fix options:
- Activate a profile.
- Provide a default bean.
- Use
@Profile("default"). - Use
@Profile("!prod")for non-production default. - Make the dependency optional if truly optional.
18. Default Profile
Spring has a default profile named:
default
If no profile is active, beans with:
@Profile("default")
can be active.
Example:
@Service
@Profile("default")
public class DefaultEmailSender implements EmailSender {
}
This bean is active only when no other profile is active.
Important:
The default profile is used when no explicit profile is active.
19. @Profile("default") vs @Profile("!prod")
@Profile("default")
Active only when no profile is explicitly active.
@Profile("default")
Useful for a basic fallback.
@Profile("!prod")
Active whenever prod is not active.
@Profile("!prod")
Active in:
dev
test
local
docker
default
Not active in:
prod
Memory sentence:
defaultmeans no profile is active.!prodmeans any profile except prod.
20. Profile-Specific Values with @ConfigurationProperties
YAML:
## application.yml
external-api:
base-url: https://api.default.com
timeout-seconds: 5
## application-prod.yml
external-api:
base-url: https://api.production.com
timeout-seconds: 20
Properties class:
@ConfigurationProperties(prefix = "external-api")
public record ExternalApiProperties(
String baseUrl,
int timeoutSeconds
) {
}
If prod is active:
baseUrl = https://api.production.com
timeoutSeconds = 20
The properties class does not need profile logic.
Spring binds the active configuration automatically.
21. Profile Groups
Spring Boot supports profile groups.
Example:
spring:
profiles:
group:
local:
- dev
- debug
- mock-email
If I activate:
--spring.profiles.active=local
Spring also activates:
dev
debug
mock-email
This is useful when one profile should activate a group of profiles.
22. Profile Include
You may also see profile include configuration.
Example:
spring:
profiles:
include: common
This includes another profile.
Profile groups are often clearer for modern apps.
Important for exam:
Know that profiles can be combined or grouped, but core exam questions usually focus on
@Profileand profile-specific files.
23. Profiles and Tests
In tests, use:
@SpringBootTest
@ActiveProfiles("test")
class UserServiceTest {
}
Then Spring loads:
application.yml
application-test.yml
And beans with:
@Profile("test")
can be active.
Example:
@TestConfiguration
@Profile("test")
public class TestConfig {
}
24. Why Use a Test Profile?
A test profile can use:
test database
fake email sender
mock external APIs
short token expiration
disabled scheduled jobs
faster configuration
Example:
## application-test.yml
spring:
datasource:
url: jdbc:h2:mem:testdb
app:
email-enabled: false
25. Profiles and Database Configuration
Example base file:
## application.yml
spring:
jpa:
hibernate:
ddl-auto: validate
Dev file:
## application-dev.yml
spring:
datasource:
url: jdbc:postgresql://localhost:5432/app_dev
username: postgres
password: postgres
Test file:
## application-test.yml
spring:
datasource:
url: jdbc:h2:mem:testdb
Prod file:
## application-prod.yml
spring:
datasource:
url: ${DB_URL}
username: ${DB_USERNAME}
password: ${DB_PASSWORD}
Same code.
Different config.
26. Profiles and Logging
Dev:
## application-dev.yml
logging:
level:
org.springframework.security: DEBUG
de.klarsync: DEBUG
Prod:
## application-prod.yml
logging:
level:
org.springframework.security: WARN
de.klarsync: INFO
Development can be more verbose.
Production should usually be less noisy.
27. Profiles and Feature Flags
Example:
## application-dev.yml
feature:
new-dashboard: true
fake-email: true
## application-prod.yml
feature:
new-dashboard: false
fake-email: false
Properties:
@ConfigurationProperties(prefix = "feature")
public record FeatureProperties(
boolean newDashboard,
boolean fakeEmail
) {
}
Then services can decide behavior based on config.
28. Profiles vs Feature Flags
Profiles are for environment-level configuration.
Feature flags are for enabling or disabling application features.
Use profiles for:
dev/test/prod environment differences
Use feature flags for:
turning a feature on/off
Do not create too many profiles just for small feature switches.
29. Profiles vs Conditions
@Profile is a kind of condition based on active profiles.
Spring Boot also has more specific conditions:
@ConditionalOnProperty
@ConditionalOnMissingBean
@ConditionalOnClass
Example:
@Bean
@ConditionalOnProperty(name = "feature.audit.enabled", havingValue = "true")
public AuditService auditService() {
return new AuditService();
}
Use @Profile for environment.
Use @ConditionalOnProperty for feature/config-based conditions.
30. Common Mistake: Profile Active in File
This can be dangerous:
## application.yml
spring:
profiles:
active: prod
Why?
Because every environment that uses this file may start with prod.
Better:
Set active profile from environment variable, command line, Docker, CI/CD, or IDE config.
For local development, it is okay to configure the IDE to use dev.
31. Common Mistake: Both Dev and Prod Active
Command:
java -jar app.jar --spring.profiles.active=dev,prod
This can cause confusing behavior.
Example:
@Profile("dev")
FakeEmailSender
and:
@Profile("prod")
RealEmailSender
Both become active.
If both implement EmailSender, injection becomes ambiguous.
Fix:
- avoid incompatible profiles together
- use profile expressions
- use
@Primaryor@Qualifiercarefully - design profile combinations intentionally
32. Common Mistake: Missing Default Bean
If I only define:
@Profile("dev")
FakeEmailSender
and:
@Profile("prod")
RealEmailSender
then with no active profile, no EmailSender exists.
If the app should run locally without explicit profile, add:
@Profile("default")
or:
@Profile("!prod")
depending on your goal.
33. Common Mistake: Expecting application-prod.yml to Load Automatically
This file:
application-prod.yml
does not load just because it exists.
It loads only when the prod profile is active.
Memory sentence:
Profile-specific files load only when their profile is active.
34. Common Mistake: Secrets in Profile Files
Bad:
## application-prod.yml
spring:
datasource:
password: real-production-password
Better:
## application-prod.yml
spring:
datasource:
password: ${DB_PASSWORD}
Then set:
DB_PASSWORD=real-secret
Do not commit real secrets.
35. Real Question: Which Config Wins?
Base:
## application.yml
server:
port: 8080
Dev:
## application-dev.yml
server:
port: 8081
Command:
java -jar app.jar --spring.profiles.active=dev --server.port=9090
Final value:
server.port = 9090
Why?
Because command-line argument overrides profile file value.
General idea:
Higher-priority external config overrides lower-priority config.
36. Real Exam Question: Active Profile
Question:
java -jar app.jar --spring.profiles.active=dev
Which files are loaded?
Answer:
Spring loads the base configuration and the dev-specific configuration:
application.yml
application-dev.yml
or:
application.properties
application-dev.properties
depending on file format.
37. Real Exam Question: @Profile
Question:
@Service
@Profile("prod")
public class RealEmailSender implements EmailSender {
}
When is this bean created?
Answer:
This bean is created only when the prod profile is active.
38. Real Exam Question: Negative Profile
Question:
@Service
@Profile("!prod")
public class ConsoleEmailSender implements EmailSender {
}
When is this bean created?
Answer:
This bean is created when the prod profile is not active.
39. Real Exam Question: Multiple Profiles
Question:
java -jar app.jar --spring.profiles.active=dev,docker
Is this valid?
Answer:
Yes. Spring can have multiple active profiles. Both dev and docker are active.
40. Real Exam Question: No Matching Profile
Question:
@Service
@Profile("dev")
public class DevPaymentProvider implements PaymentProvider {
}
@Service
@Profile("prod")
public class ProdPaymentProvider implements PaymentProvider {
}
No profile is active.
What happens if another bean requires PaymentProvider?
Answer:
No PaymentProvider bean is created, so Spring fails to start with a missing bean error.
41. Real Exam Question: Default Profile
Question:
What is the default profile?
Answer:
The default profile is active when no other profile is explicitly active. Beans annotated with @Profile("default") can be created when no profile is set.
42. Real Exam Question: default vs !prod
Question:
What is the difference between @Profile("default") and @Profile("!prod")?
Answer:
@Profile("default") is active only when no profile is explicitly active. @Profile("!prod") is active whenever the prod profile is not active, including dev, test, local, or default mode.
43. Real Exam Question: application-prod.yml
Question:
Does application-prod.yml load automatically because the file exists?
Answer:
No. It loads only when the prod profile is active.
44. Real Exam Question: Test Profile
Question:
How do I activate the test profile in a Spring Boot test?
Answer:
Use:
@ActiveProfiles("test")
Example:
@SpringBootTest
@ActiveProfiles("test")
class MyTest {
}
45. Real Exam Question: Profiles vs Properties
Question:
Should I use profiles or feature flags for turning on one small feature?
Answer:
Usually use a feature flag or property, not a new profile. Profiles are better for environment-level configuration such as dev, test, prod, or docker.
46. Interview Answer
Question:
What are Spring profiles?
Good answer:
Spring profiles allow us to define different beans and configuration for different environments, such as dev, test, and prod. A profile can activate profile-specific configuration files like application-dev.yml and beans annotated with @Profile("dev"). This helps us run the same application code with different environment-specific settings.
47. Interview Answer
Question:
How do profile-specific configuration files work?
Good answer:
Spring Boot always loads the base configuration file, such as application.yml. If a profile is active, for example dev, Spring also loads application-dev.yml. Values from the profile-specific file can override values from the base file. The profile can be activated with spring.profiles.active, an environment variable, a command-line argument, or @ActiveProfiles in tests.
48. Interview Answer
Question:
What does
@Profiledo?
Good answer:
@Profile controls whether a bean or configuration class is active for a specific profile. For example, @Profile("dev") means the bean is created only when the dev profile is active. It can be used on classes, configuration classes, or @Bean methods. It is useful when different environments need different bean implementations.
49. Interview Answer
Question:
How do you activate a profile in Spring Boot?
Good answer:
A profile can be activated in several ways. For example, with a command-line argument like --spring.profiles.active=prod, with an environment variable like SPRING_PROFILES_ACTIVE=prod, in an IDE run configuration, or in tests using @ActiveProfiles("test"). In production, it is usually better to activate profiles through environment or deployment configuration rather than hardcoding them in application.yml.
50. Interview Answer
Question:
What problems can profiles cause?
Good answer:
Profiles can cause missing bean errors if no active profile matches the required bean. They can also cause ambiguity if multiple profiles are active and multiple beans of the same type are created. Another common problem is expecting a profile-specific file like application-prod.yml to load automatically even though the prod profile is not active. It is important to design profile usage clearly and avoid incompatible profiles being active together.
51. Tiny Code Practice
Create this interface:
public interface StorageService {
void store(String fileName);
}
Dev implementation:
@Service
@Profile("dev")
public class LocalStorageService implements StorageService {
@Override
public void store(String fileName) {
System.out.println("Storing locally: " + fileName);
}
}
Prod implementation:
@Service
@Profile("prod")
public class S3StorageService implements StorageService {
@Override
public void store(String fileName) {
System.out.println("Uploading to S3: " + fileName);
}
}
Usage:
@Service
public class DocumentService {
private final StorageService storageService;
public DocumentService(StorageService storageService) {
this.storageService = storageService;
}
}
Questions:
- Which bean is created when
devis active? - Which bean is created when
prodis active? - What happens when no profile is active?
Answers:
LocalStorageServiceS3StorageService- No
StorageServicebean exists, so the app may fail unless a default bean is provided.
52. Tiny Bug Practice
Problem:
@Service
@Profile("dev")
public class FakeEmailSender implements EmailSender {
}
@Service
@Profile("prod")
public class RealEmailSender implements EmailSender {
}
Command:
java -jar app.jar --spring.profiles.active=dev,prod
Question:
What is the problem?
Answer:
Both FakeEmailSender and RealEmailSender become active. If another bean requires EmailSender, Spring finds two candidates and may fail with an ambiguity error unless one is marked @Primary, selected with @Qualifier, or the profiles are designed to be mutually exclusive.
Practice Questions and Answers
Question 1
What is a Spring profile?
Answer:
A Spring profile is a named environment mode that controls which configuration and beans are active.
Question 2
Why do we need profiles?
Answer:
Profiles are needed because different environments, such as local, test, and production, need different configuration and sometimes different bean implementations.
Question 3
Name three common profiles.
Answer:
Common profiles are:
dev
test
prod
Other common ones are:
local
docker
ci
staging
Question 4
What file is loaded for the dev profile?
Answer:
For the dev profile, Spring Boot loads:
application.yml
application-dev.yml
or the equivalent .properties files.
Question 5
Does application-prod.yml load automatically just because it exists?
Answer:
No. application-prod.yml loads only when the prod profile is active.
Question 6
How can I activate the prod profile from the command line?
Answer:
Use:
java -jar app.jar --spring.profiles.active=prod
Question 7
How can I activate the prod profile with an environment variable?
Answer:
Use:
SPRING_PROFILES_ACTIVE=prod java -jar app.jar
Question 8
How can I activate the test profile in a test?
Answer:
Use:
@ActiveProfiles("test")
Example:
@SpringBootTest
@ActiveProfiles("test")
class MyTest {
}
Question 9
What does @Profile("dev") mean?
Answer:
@Profile("dev") means the bean or configuration is active only when the dev profile is active.
Question 10
Can @Profile be used on @Bean methods?
Answer:
Yes. @Profile can be used on @Bean methods.
Question 11
Can @Profile be used on a whole configuration class?
Answer:
Yes. @Profile can be used on a whole configuration class. Then all beans in that configuration class are active only when the profile matches.
Question 12
Can multiple profiles be active at the same time?
Answer:
Yes. Multiple profiles can be active at the same time, for example dev,docker.
Question 13
What does @Profile("!prod") mean?
Answer:
@Profile("!prod") means the bean is active when the prod profile is not active.
Question 14
What does @Profile("dev | test") mean?
Answer:
@Profile("dev | test") means the bean is active when either dev or test is active.
Question 15
What does @Profile("dev & docker") mean?
Answer:
@Profile("dev & docker") means the bean is active only when both dev and docker profiles are active.
Question 16
What is the default profile?
Answer:
The default profile is active when no other profile is explicitly active.
Question 17
What is the difference between @Profile("default") and @Profile("!prod")?
Answer:
@Profile("default") is active only when no explicit profile is active. @Profile("!prod") is active whenever the prod profile is not active, including dev, test, local, or default mode.
Question 18
What happens if no profile-specific bean matches a required dependency?
Answer:
If no matching bean exists for a required dependency, Spring usually fails to start with a missing bean error.
Question 19
What happens if both dev and prod profiles are active and both create the same interface bean?
Answer:
Both beans may become active. If both implement the same interface and another bean needs that interface, Spring may fail with an ambiguity error unless the ambiguity is resolved.
Question 20
What is the difference between profiles and feature flags?
Answer:
Profiles are for environment-level configuration such as dev, test, and prod. Feature flags are for enabling or disabling specific application features.
Final Memory Sentences
- A Spring profile controls which configuration and beans are active.
- Common profiles are
dev,test, andprod. application.ymlis base configuration.application-dev.ymlloads only whendevis active.- Profile-specific files override base configuration.
@Profile("dev")creates a bean only whendevis active.@Profile("!prod")creates a bean whenprodis not active.- Multiple profiles can be active at the same time.
@Profile("default")is active only when no explicit profile is active.- Activate profiles with command-line arguments, environment variables, IDE config, or
@ActiveProfilesin tests. - Do not commit real production secrets into profile files.
- Avoid activating incompatible profiles together.
- Profiles are for environments.
- Feature flags are for application features.