In this article, we will configure profiles in a Spring Boot multi-module project and separate environment-specific configurations (local/dev/prod) using application-{profile}.yml.
Profile separation is essential in real-world backend applications because it prevents development and production settings from mixing and helps maintain security and manageability.
📌 Spring Boot(Kotlin) Basic Setup — Full Series
- Why Multi-Module Architecture? (Architecture philosophy & overall design)
- API Response Format Design
- Global Exception Handling (GlobalExceptionHandler)
- Swagger (OpenAPI) Configuration
- Security (JWT) Basic Structure
- JWT TokenProvider
- Redis Configuration
- Validation Setup
- Logging + MDC(traceId) Configuration
- application.yml Profile Separation (local/dev/prod) ← this article
- Multi-Module + JPA Basic Structure
- Final Project Template (git) Sharing
✔ Why Profile Separation Is Necessary
Backend applications require different configuration values depending on the environment.
For example:
- Local development → Local DB, local Redis
- Development server (dev) → Dev DB, dev JWT secret
- Production server (prod) → Production DB, enhanced security settings
If all configurations are mixed inside a single application.yml, several issues can occur:
- Production credentials or secrets may leak into source code (security risk)
- Local testing accidentally connects to dev/prod DB → potential system failure
- Environment-specific configurations become difficult to manage
Therefore, Spring Boot strongly recommends using profiles to separate environment-specific configurations. In real-world projects, local / dev / prod separation is considered essential.
✔ application.yml — Base Configuration
The base application.yml contains only common settings and the default active profile.
application.yml
server:
port: 8080
spring:
profiles:
active: local # Default is local environment
logging:
pattern:
console: "%d{yyyy-MM-dd HH:mm:ss} [traceId=%X{traceId}] [eventId=%X{eventId}] [userId=%X{userId}] [ip=%X{clientIp}] %-5level %logger{36} - %msg%n"
Here, we define the console log pattern and set the default active profile to local.
In our previous Logging + MDC setup, we configured multiple MDC fields such as traceId, eventId, userId, and clientIp. After updating the log pattern based on that configuration, the actual log output will look like the following:
2025-02-01 23:10:22 [traceId=ca21ef01] [eventId=ABCD1234] [userId=42] [ip=123.45.67.89] ERROR c.e.a.UserService - [Unexpected Error]
method=com.example.UserService.createUser(L52)
rootCause=java.lang.IllegalStateException: something went wrong
With this format, it becomes significantly easier to trace individual requests, identify the exact user who triggered the error, and quickly investigate issues across different environments.
✔ application-dev.yml — Development Environment
application-dev.yml
spring:
config:
activate:
on-profile: dev
datasource:
url: ${DEV_DB_URL}
username: ${DEV_DB_USERNAME}
password: ${DEV_DB_PASSWORD}
driver-class-name: com.mysql.cj.jdbc.Driver
jpa:
hibernate:
ddl-auto: none
properties:
hibernate:
format_sql: false
open-in-view: false
jwt:
secret: ${DEV_JWT_SECRET}
redis:
host: ${REDIS_HOST}
port: ${REDIS_PORT}
The development environment is usually deployed on AWS, GCP, or an internal dev server.
All critical values (DB, Redis, JWT secret) are injected via environment variables.
✔ application-local.yml — Local Development
application-local.yml
spring:
config:
activate:
on-profile: local
datasource:
url: ${LOCAL_DB_URL:}
username: ${LOCAL_DB_USERNAME:}
password: ${LOCAL_DB_PASSWORD:}
driver-class-name: com.mysql.cj.jdbc.Driver
jpa:
hibernate:
ddl-auto: none
properties:
hibernate:
format_sql: true
open-in-view: false
# Base64 encoded dummy key (real secrets should be overridden in dev/prod)
jwt:
secret: dGVtcG9yYXJ5LXNlY3JldC1rZXktZm9yLWxvY2FsLWRldg==
redis:
host: localhost
port: 6379
For local development:
- format_sql = true → SQL logs become easier to read
- dummy JWT key → prevents real secrets from being stored in source code
- Local DB & Redis used for convenience
✔ application-prod.yml — Production Environment
application-prod.yml
spring:
config:
activate:
on-profile: prod
datasource:
url: ${PROD_DB_URL}
username: ${PROD_DB_USERNAME}
password: ${PROD_DB_PASSWORD}
driver-class-name: com.mysql.cj.jdbc.Driver
jpa:
hibernate:
ddl-auto: none
properties:
hibernate:
format_sql: false
open-in-view: false
jwt:
secret: ${PROD_JWT_SECRET}
redis:
host: ${REDIS_HOST}
port: ${REDIS_PORT}
In production:
- Production DB credentials are never stored in source code
- SQL formatting disabled (format_sql = false) for performance
- JWT secret loaded fromprod-level environment variables
- All external service credentials use environment variables
✔ How Profile Resolution Works
Spring Boot loads configurations in the following order:
application.yml → check active profile →
application-{profile}.yml → override settings
To run in production:
java -jar app.jar --spring.profiles.active=prod
→ application.yml is loaded → application-prod.yml overrides environment-specific settings
✔ Why Profile Separation Is Beneficial
1) Security
- Production DB credentials and JWT secrets never leak into source code
- Everything sensitive is injected via environment variables
2) Prevent Configuration Mistakes
- Prevents accidental use of production DB during local development
- Dev environment testing won't affect real production data
3) Deploy Easily with CI/CD
- Simply change the profile during deployment
- One codebase supports three environments
4) Easier Maintenance
- Environment-specific settings are clearly separated
- Team collaboration becomes safer and smoother
✔ Conclusion
Separating application.yml profiles is essential even for small projects.
Once your project has development and production environments, profile separation dramatically improves security, stability, and maintainability.
The next article will cover Multi-Module + JPA Basic Structure.
https://jaemoi8.tistory.com/49
Spring Boot(Kotlin) — ep.11 Structuring JPA in a Spring Boot Multi-Module Architecture
In this article, we will organize how JPA should be placed within a Spring Boot multi-module projectand summarize the key concepts you need to understand during the initial setup.Since the goal of this series is to build a “basic server setup template,
jaemoi8.tistory.com