βSpring Profiles are like different outfits for your app. It wears shorts and a t-shirt for a casual ‘dev’ day at home, but a full suit for a professional ‘prod’ meeting. ππβ
Your application is a versatile creature. In the development jungle, it needs to be nimble, connect to a local database, and chatter away with verbose logging. But in the production savanna, it must be robust, connect to a secure production database, and speak only when something important happens. How do you manage these different wardrobes without a messy closet of commented-out code and last-minute property changes? The professional’s choice is Spring Profiles.
Problem Statement: The Chaos of One-Size-Fits-All Configuration
Imagine you have a single application.properties
file. Before you push to production, you frantically comment out the H2 database URL and uncomment the PostgreSQL one. You change the log level from DEBUG
to WARN
. You swap out a local Stripe test key for the real one. This approach is a recipe for disaster:
- It’s error-prone: It’s incredibly easy to forget a change and accidentally deploy with development settings.
- It’s not scalable: What happens when you add a QA, staging, or UAT environment? The file becomes an unmanageable mess of commented-out sections.
- It pollutes version control: Your commit history gets filled with trivial configuration changes that are just noise.
This isn’t how the wise old monkeys of the jungle operate. They have a system. That system is Spring Profiles.
The “Right” Way: Dressing Your App with Profiles
Spring Profiles allow you to define and segregate configuration properties for different environments. You create separate property files for each environment (your app’s “outfits”), and then simply tell Spring which one to wear at startup. The base application.properties
file acts as the default, common wardrobe for all environments.
1οΈβ£ Creating Profile-Specific Property Files
The naming convention is simple: application-{profileName}.properties
. Let’s create a few outfits for our application.
src/main/resources/application.properties
(The Base Outfit – Common to All)
# This property is the same for all environments
spring.application.name=jungle-blog
# Default server port if no profile is active
server.port=8080
src/main/resources/application-dev.properties
(The “Casual Dev” T-Shirt and Shorts)
# Use a different port to avoid conflicts locally
server.port=8081
# Connect to a local, in-memory H2 database
spring.datasource.url=jdbc:h2:mem:devdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=password
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
# Enable the H2 console for easy database inspection
spring.h2.console.enabled=true
# Show SQL and be verbose with logging
logging.level.org.springframework=DEBUG
logging.level.org.hibernate.SQL=DEBUG
src/main/resources/application-prod.properties
(The “Professional Prod” Suit)
# Use the standard HTTP port
server.port=80
# Connect to the secure, production PostgreSQL database
spring.datasource.url=jdbc:postgresql://prod-db.jungle.com:5432/blogdb
spring.datasource.driverClassName=org.postgresql.Driver
spring.datasource.username=prod_user
# DON'T hardcode passwords here. Use environment variables instead.
spring.datasource.password=${DB_PASSWORD}
spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect
# Less verbose logging for production
logging.level.org.springframework=WARN
Properties in the active profile’s file will override those in the default application.properties
. If a property isn’t defined in the active profile, the default one is used.
2οΈβ£ Activating the Right Profile
Telling your app which outfit to wear is easy. You have several options, with a clear order of precedence.
- In
application.properties
: Good for setting a default profile.spring.profiles.active=dev
- As a Command-Line Argument: Overrides the property file. This is very common for startup scripts.
java -jar my-app.jar --spring.profiles.active=prod
- As an Environment Variable: Overrides the property file, but is overridden by command-line args. Ideal for Docker and CI/CD environments.
export SPRING_PROFILES_ACTIVE=prod java -jar my-app.jar
- In your IDE: Most IDEs (like IntelliJ) let you specify active profiles in the run configuration, which is great for local development.
3οΈβ£ The YAML Advantage: All Outfits in One Closet
While separate .properties
files are great, you can also manage all your profiles in a single application.yml
file using the triple-dash (---
) separator. This can be easier to manage and visualize.
# Default properties (no profile specified)
spring:
application:
name: jungle-blog
server:
port: 8080
---
# "dev" profile
spring:
config:
activate:
on-profile: "dev"
server:
port: 8081
logging:
level:
org.springframework: DEBUG
datasource:
url: jdbc:h2:mem:devdb
---
# "prod" profile
spring:
config:
activate:
on-profile: "prod"
server:
port: 80
logging:
level:
org.springframework: WARN
datasource:
url: jdbc:postgresql://prod-db.jungle.com:5432/blogdb
password: ${DB_PASSWORD}
π‘ Monkey-Proof Tips
- Profile Precedence is Key: Remember the order: Command-Line Arguments > Environment Variables >
application.properties
. This allows you to set a safe default (like ‘dev’) and override it in your production environment. - The ‘default’ Profile: If no profile is active, Spring uses a profile named
default
. You can create anapplication-default.properties
file to provide explicit defaults if you wish. - Activate Multiple Profiles: You can activate multiple profiles by separating them with a comma (e.g.,
--spring.profiles.active=prod,aws
). This lets you layer configurations. Properties from later profiles in the list will override earlier ones. - Profile Groups (Spring Boot 2.4+): For complex scenarios, you can group profiles together in your base
application.properties
or.yml
file. Activating the group name activates all profiles within it.
Then, you can just activate the “production” group:# In application.properties spring.profiles.group.production=prod,aws-logging,external-secrets
--spring.profiles.active=production
.
π Challenge
Time to organize your application’s wardrobe! Refactor your project to use profiles correctly.
- Create Three Profiles: Create configuration files for three environments:
dev
: Uses an H2 in-memory database and sets the logging level for Spring toINFO
.staging
: Connects to a local PostgreSQL database (you can use one from Testcontainers or Docker) and sets the logging level for Spring toWARN
.prod
: Sets up a placeholder configuration for a production PostgreSQL database (use placeholder text like"jdbc:postgresql://prod-db..."
) and sets the logging level toERROR
.
- Set a Default: In your main
application.properties
, set the default active profile todev
. - Verify Each Profile:
- Run your application normally. Check the logs to confirm it started on the
dev
profile and see the INFO logs. - Stop the application. Run it again from the command line, but this time add the argument:
--spring.profiles.active=staging
. Check the logs to verify the correct profile is active. - Run it one more time using an environment variable for the
prod
profile and check the logs.
- Run your application normally. Check the logs to confirm it started on the
π You’ve successfully tamed the chaos of environment-specific configuration! By using Spring Profiles, your application is now a well-dressed professional, ready for any occasion, from a casual development session to a high-stakes production deployment.