Spring Boot Profiles
Learn how application-dev.properties and application-prod.properties let you maintain separate configuration per environment, and how to activate a profile.
Introduction
The datasource configuration you wrote in the last lesson pointed at a local database with a local password — exactly right for your machine, and exactly wrong for a production server. Every real application needs different configuration depending on where it's running: different database credentials, different logging levels, different feature flags. Spring Boot profiles solve this cleanly, letting you maintain multiple sets of configuration and switch between them with a single setting.
- Why hardcoding one configuration for every environment is a problem.
- How application-dev.properties and application-prod.properties work.
- How to activate a specific profile at startup.
- How @Profile controls which beans get created in each environment.
Why Profiles Exist
Consider the datasource URL and password from Lesson 21: fine for local development, but a production deployment needs a different host, different credentials, and probably ddl-auto=validate instead of update, since you never want Hibernate silently altering a production schema. Without profiles, you'd need to manually edit application.properties every time you moved between environments — error-prone and easy to get wrong at exactly the wrong moment.
Profile-Specific Property Files
Spring Boot recognizes files named application-{profile}.properties automatically, alongside your base application.properties. Values in a profile-specific file override the base file when that profile is active.
# application.properties (shared, always loaded)spring.application.name=student-apispring.jpa.show-sql=false# application-dev.propertiesspring.datasource.url=jdbc:mysql://localhost:3306/studentdbspring.datasource.username=rootspring.datasource.password=devpassword
spring.jpa.hibernate.ddl-auto=updatespring.jpa.show-sql=truelogging.level.org.springframework=DEBUG# application-prod.propertiesspring.datasource.url=jdbc:mysql://prod-db.internal:3306/studentdbspring.datasource.username=${DB_USERNAME}spring.datasource.password=${DB_PASSWORD}
spring.jpa.hibernate.ddl-auto=validatespring.jpa.show-sql=falselogging.level.org.springframework=WARNNotice how the production file references ${DB_USERNAME} and ${DB_PASSWORD} rather than hardcoding real credentials — Spring Boot resolves these from environment variables at startup, keeping secrets out of version control entirely.
Activating a Profile
A profile is activated by setting spring.profiles.active, which can be done in several ways depending on how you're running the application.
# In application.properties, to set a defaultspring.profiles.active=dev# As a command-line argument when running the packaged jarjava -jar student-api.jar --spring.profiles.active=prod
# As an environment variableexport SPRING_PROFILES_ACTIVE=prodjava -jar student-api.jarClick Run to see what this code prints.
The @Profile Annotation
Beyond property files, the @Profile annotation controls whether an entire Spring bean or configuration class is created at all, depending on the active profile. This is useful for swapping entire implementations — for example, a fake email sender for development versus a real one for production.
@Service@Profile("dev")public class FakeEmailService implements EmailService { @Override public void send(String to, String subject, String body) { System.out.println("[DEV] Would send email to " + to + ": " + subject); }}@Service@Profile("prod")public class RealEmailService implements EmailService { @Override public void send(String to, String subject, String body) { // Actual SMTP/API integration here }}When two beans implement the same interface but are annotated for different profiles, Spring only creates the one matching the active profile — so exactly one EmailService bean exists at runtime, and the rest of your code can simply inject EmailService without knowing which environment it's running in.
Common Mistakes
- Committing real production credentials into application-prod.properties instead of referencing environment variables.
- Forgetting to set spring.profiles.active anywhere, so the application silently falls back to only the base application.properties.
- Leaving spring.jpa.hibernate.ddl-auto=update active in a production profile, risking unintended schema changes.
- Naming a profile file incorrectly, such as application_dev.properties (underscore) instead of application-dev.properties (hyphen), which Spring Boot won't recognize.
Best Practices
- Keep at least a dev and a prod profile from early in a project's life, even if they start out nearly identical.
- Use ddl-auto=validate or none in production, and reserve update strictly for local development.
- Reference sensitive values like passwords through environment variable placeholders, never as literal text in a properties file.
- Use @Profile to swap entire bean implementations when environments genuinely need different behavior, not just different property values.
Frequently Asked Questions
Yes. spring.profiles.active accepts a comma-separated list, such as --spring.profiles.active=prod,metrics, and Spring Boot merges properties and beans from every listed profile.
They still load first as the shared base configuration. Profile-specific files layer on top and override any matching keys, while properties not redefined in the profile file keep their base value.
Yes, Spring Boot uses an implicit profile named default when spring.profiles.active isn't set. Only application.properties (and application-default.properties, if present) applies in that case.
Yes, a test profile (application-test.properties) is a common convention, often pointing at an in-memory H2 database so automated tests never touch a real development or production database.
Key Takeaways
- Spring Boot profiles let you maintain separate configuration per environment using application-{profile}.properties files.
- spring.profiles.active, set via property, environment variable, or command-line argument, controls which profile is used.
- Profile-specific properties override the shared application.properties for matching keys.
- @Profile controls which entire bean implementations are created, not just individual property values.
Summary
You can now maintain clean, separate configuration for development and production, and switch between them safely without editing code. Next, you'll step back from configuration and look at how Spring Boot wires all these beans together in the first place, with a deep dive into Dependency Injection.