Spring Boot supports flexible environment variable interpolation in your application.yml
files, but it's important to know when to require a variable, leave it empty, or provide a default value.
Choosing the right approach improves reliability, avoids silent misconfigurations, and makes your application easier to maintain across environments.
Letβs break it down into three types:
π 1. ${VARIABLE}
β Required
This format means the variable must be defined.
If it's not present, Spring Boot will fail to start with an error.
β
When to use:
Use this for critical configuration values your application canβt run without:
- Database connection details
- API credentials
- Encryption keys
spring:
datasource:
url: ${DB_URL} # Must be set
username: ${DB_USER} # Must be set
password: ${DB_PASS} # Must be set
π‘ 2. ${VARIABLE:}
β Optional (empty by default)
This syntax allows the variable to be undefined, in which case it defaults to an empty string.
β
When to use:
Use when the value is not always required, and you will handle its presence at runtime.
external:
api-key: ${EXTERNAL_API_KEY:} # Will be empty if not defined
π Remember to check if it's empty before using it in your code.
π’ 3. ${VARIABLE:default}
β Optional with fallback value
This format sets a default value if the variable is not defined.
β
When to use:
Use when a sensible default exists and makes development easier. This avoids overconfiguring every environment unnecessarily.
server:
port: ${SERVER_PORT:8080} # Uses port 8080 if not set
β Best Practices Summary
Purpose | Syntax |
---|---|
Required, critical configuration | ${VAR} |
Optional, check at runtime | ${VAR:} |
Optional, default fallback | ${VAR:default-value} |
π Example: application.yml
with Best Practices
spring:
profiles:
active: ${SPRING_PROFILES_ACTIVE:dev} # Default to 'dev'
datasource:
url: ${DB_URL} # β Required
username: ${DB_USERNAME} # β Required
password: ${DB_PASSWORD} # β Required
driver-class-name: ${DB_DRIVER:com.mysql.cj.jdbc.Driver} # β
Default fallback
jpa:
hibernate:
ddl-auto: ${HIBERNATE_DDL:auto} # β
Default
server:
port: ${SERVER_PORT:8080} # β
Default port
servlet:
context-path: ${CONTEXT_PATH:/}
client:
id: ${CLIENT_ID:localhost} # β
Fallback value for local use
api-key: ${EXTERNAL_API_KEY:} # πΈ Optional
management:
endpoint:
env:
show-values: WHEN_AUTHORIZED # Safer than ALWAYS
endpoints:
web:
base-path: /actuator
exposure:
include: health,info
security:
jwt:
secret: ${JWT_SECRET} # β Required
expiration: ${JWT_EXPIRATION:3600} # β
Default in seconds
app:
environment: ${APP_ENVIRONMENT:local}
feature-flag:
enable-beta: ${ENABLE_BETA_FEATURE:false}
π‘οΈ Final Advice
Always document which environment variables are mandatory and validate them early when possible. This avoids surprises during deployment and improves your systemβs robustness.
Top comments (0)