Profile-Specific Properties Files with Maven
Fast recall
Quick revision
Core answer
mvn package -P... can create a profile-specific artifact. Enable filtering explicitly and use the delimiter expected by the Spring Boot parent. Do not bake passwords or other secrets into the artifact; for most application environments, build once and supply Spring configuration at runtime.Practical knowledge of Maven resource filtering and profile-specific configuration management
Hardcoding secrets like database passwords into properties files committed to version control and packaged into the JAR
Point out that packaging secrets into the artifact is a security antipattern — better to inject values via environment variables at runtime or use a secrets vault
Interview-ready guide
Interview answer
Maven resource filtering lets you inject profile-specific values into property files during the build.
Here's how it works. url}. url.
The dev profile might set it to jdbc:h2:mem:devdb, while the prod profile sets it to the actual production PostgreSQL URL. The key step is enabling filtering in the build section — I'd add a resource configuration with filtering set to true. properties into the JAR but replaces all the placeholders with production values.
The packaged JAR contains the final substituted values, not the placeholders. One critical mistake freshers make is hardcoding secrets in these profiles. xml and committing it.
That's a security nightmare because the password ends up in Git history and baked into the JAR. DB_PASSWORD}, so Maven pulls the secret from an environment variable during the build. Even better, don't use Maven filtering for secrets at all.
Use Spring's externalized configuration to inject secrets at runtime via environment variables or a secrets vault. That way, secrets never touch your codebase or artifacts. Another point: Maven resource filtering creates environment-specific JARs, which violates the build once, deploy everywhere principle.
jar separately, so you're not testing the exact artifact you deploy. Modern best practice is to build one JAR and use Spring profiles or environment variables to change behavior at runtime. Maven resource filtering is useful for non-sensitive config like feature flags or API timeouts, but for critical config like database credentials, inject at runtime.
Profile-Specific Properties Files with Maven
Direct Answer
A Maven profile can select a resource directory or provide values used by Maven resource filtering, so mvn package -P... can create a profile-specific artifact. Enable filtering explicitly and use the delimiter expected by the Spring Boot parent. Do not bake passwords or other secrets into the artifact; for most application environments, build once and supply Spring configuration at runtime.
Code Example
<profiles>
<profile>
<id>dev</id>
<properties>
<db.url>jdbc:h2:mem:devdb</db.url>
<db.username>sa</db.username>
<db.password></db.password> <!-- empty for H2 -->
<logging.level>DEBUG</logging.level>
</properties>
</profile>
<profile>
<id>prod</id>
<properties>
<db.url>jdbc:postgresql://prod-db.example.com:5432/orders</db.url>
<db.username>app_user</db.username>
<db.password>${env.DB_PASSWORD}</db.password> <!-- from environment variable -->
<logging.level>WARN</logging.level>
</properties>
</profile>
</profiles>
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering> <!-- enables placeholder substitution -->
</resource>
</resources>
</build>
<!-- In src/main/resources/application.properties: -->
<!-- spring.datasource.url=${db.url} -->
<!-- spring.datasource.username=${db.username} -->
<!-- spring.datasource.password=${db.password} -->
<!-- logging.level.root=${logging.level} -->
Common Mistakes & Pitfalls
- Hardcoding secrets in profiles: The biggest mistake is defining <db.password>prod123</db.password> directly in a Maven profile and committing it to Git. This leaks credentials into version control history and packages them into the JAR, where anyone with access to the artifact can extract them. Always use ${env.DB_PASSWORD} syntax to pull secrets from environment variables at build time, or better yet, inject them at runtime using Spring's externalized configuration.
- Violating build once, deploy everywhere: Maven resource filtering creates different JARs for different environments, which violates a core DevOps principle. If you build dev.jar and prod.jar separately, you're not testing the same artifact you're deploying. A better approach is to build one JAR and use Spring profiles or environment variables to inject config at runtime.
- Forgetting to enable filtering: Freshers define placeholders and profiles but forget to add <filtering>true</filtering> in the build resources section. Without this, Maven copies files verbatim without substituting placeholders, and your app starts with literal ${db.url} strings.
Check your understanding
Answer these without looking back at the article.
- What is the 12-factor app methodology?
- How does Spring Boot's application-{profile}.properties work?
Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.