I scanned 50 open-source Spring Boot projects for config drift. 53% had issues that wouldn't fail a single test.
I got tired of manually diffing application-dev.yml against application-prod.yml before every deployment. So I built a small CLI to do it automatically — and then ran it against 50 well-known Spring Boot projects on GitHub to see how widespread the problem actually is.
The short version: 26 out of 50 projects had at least one issue.
The three patterns I kept seeing
1. The Actuator leak
# application-dev.yml
management.endpoints.web.exposure.include: "*"
Completely reasonable in dev. Dangerous when it drifts into prod. /actuator/env returns all your environment variables — including secrets. /actuator/heapdump lets anyone download a full JVM heap dump.
The Spring PetClinic — Spring's own reference application — ships with include: * as a default. 78 modules across the scanned projects had this.
2. The database schema destroyer
# application-dev.yml
spring.jpa.hibernate.ddl-auto: update
Convenient in dev. If it drifts into prod and your entity model changes, Hibernate silently modifies your production schema. No migration script, no warning. I've seen this kill a database.
3. The missing feature flag
# dev + staging: feature.new-payment-flow.enabled: true
# prod: (key doesn't exist)
Spring Boot falls back to null. If you're lucky you get a NullPointerException at startup. If you're not, it silently disables a feature in production that worked fine in every test environment.
Why this is so hard to catch
Code review won't find it — you're looking at diffs, not at the relationship between files. Tests won't find it — they run against one profile. CI won't find it — the app starts fine.
The tool
I built spring-drift to catch this in CI or as a pre-deploy check:
$ spring-drift scan ./src/main/resources
✓ Found 4 profiles: default, dev, staging, prod
✗ 7 drift issues found
[DANGEROUS_DEFAULT] management.endpoints.web.exposure.include
default: health,info
dev: *
prod: * ← matches dev — likely accidental
[DANGEROUS_DEFAULT] spring.jpa.hibernate.ddl-auto
dev: update
prod: update ← destructive in production
[MISSING_KEY] feature.new-payment-flow.enabled
dev: true
prod: <missing> ← will fall back to null
Report written to drift-report.md
Single binary via GraalVM Native Image (no JRE needed), ~26ms on a real project, outputs Markdown you can paste into a PR.
GitHub: https://github.com/jolle93/spring-boot-config-drift-detector
Docs + download: https://julianpaul.dev/spring-drift