Application Configuration Management: 10 Production-Ready Mistakes to Avoid
Misconfigured timeouts, secrets, or resource limits cause outages faster than logic bugs. Unlike code, configuration often bypasses code review, automated tests, and CI pipelines—creating silent risks: services writing to the wrong database, exhausting connection pools, or leaking credentials. Real-world incident analysis uncovered 10 subtle misconfigurations that remain hidden until failure strikes.
Hardcoded Timeouts: 30+ Instances Across Code
Hardcoding timeouts in source requires full rebuilds for adjustments. A grep for Duration.ofSeconds revealed over 30 scattered instances with inconsistent values: 10s in NotificationService, 30s in SearchService, 15s in ApiRoutes.
private static final Duration TIMEOUT = Duration.ofSeconds(10); // NotificationService
private static final Duration TIMEOUT = Duration.ofSeconds(30); // SearchService
private static final Duration TIMEOUT = Duration.ofSeconds(10); // AuthFilter
private static final Duration TIMEOUT = Duration.ofSeconds(15); // ApiRoutes
Under load, timeout tuning is critical—but hardcoding kills agility. Fix: Externalize into config with environment-variable overrides.
Missing Validation: Accidentally Wiping Production Databases
A 695-line config class validates only one parameter. All others are accepted blindly: connection pool = 0, timeout = -1, empty DB URL.
String authType = config.getString("authType");
if (!Set.of("kerberos", "jwt").contains(authType)) {
throw new IllegalArgumentException("Invalid auth type, possible values are kerberos, jwt");
}
Dangerous examples include http.server.parsing.max-content-length = 10g: a single request consumes 10 GB RAM. Or Liquibase’s dropAll = ${?DROP_ALL}—which drops your entire schema without confirmation. Fail-fast at startup prevents incidents.
Default Values That Mask Failures
Defaults hide missing keys until runtime. When enabling SSO:
Duration maxResponseDelay = ssoEnabled
? config.getDuration("sso.maxResponseDelay")
: Duration.ofMinutes(10);
long responseCacheSize = ssoEnabled
? config.getLong("sso.responseCacheSize")
: 10_000;
Missing keys crash production. Similarly, tokenTtl silently defaults from 1min (config) to 3min (code), violating security policies.
- The default trap: Misconfigurations stay invisible until feature activation.
- Solution: Validate all required keys at startup; log warnings on fallback usage.
Configuration Drift Between Test and Production
Test configs diverge from production by orders of magnitude:
| Parameter | Production | Test |
|-----------|------------|------|
| api.responseLimit | 10 MB | 1 GB |
| api.contextLimit | 10 MB | 1 MB |
A 50 MB response passes tests but fails in production. Conversely, stricter test configs yield false negatives.
Inconsistent Parameter Naming
One application.conf mixes naming styles:
fileStoragePath = "/opt/storage" # camelCase
retention-days = 7 # kebab-case
createdump-interval-seconds = 240 # hybrid
usage-threshold = 80 # kebab-case
compressHeapDump = true # camelCase
Booleans vary wildly: sslValidationEnabled, smtpSslEnable, saml.enabled, isUseSecureCookieJWT. Environment overrides fail silently: smtpSslEnable → SMTP_SSL_ENABLED (but Enable ≠ Enabled).
- Mixing
camelCaseandkebab-casein one file. - HOCON/env key mismatches.
- Four distinct boolean flag conventions.
Zombie Feature Flags Without Lifecycle Management
16 flags in the Config class: ws-cache-enabled=false everywhere, history-import-enabled=true always. No creation dates, owners, or removal rationale—cognitive load mounts.
- Add: Creation date, owner, purpose, and deprecation deadline.
- Remove: Immortal flags—always
true/falseand never used.
Incorrect HOCON Override Order
In HOCON, the last value wins. Correct:
key = "default-value"
key = ${?ENV_OVERRIDE}
Incorrect:
dump {
enabled = ${?DUMP_ENABLED}
enabled = false
directory = ${?DUMP_DIR}
directory = "opt/myapp/dumps/auto"
}
Environment override is overwritten by false—dumps stay disabled.
Undocumented Config: 100+ Parameters, Zero Clarity
docker.md lists env vars like EMAIL_ENABLED=false/true—no descriptions. AppConfig.java spans 695 lines with zero Javadoc. What does sync-request-timeout-seconds=600 control? What happens if workflowStepLimit=200 hits 0 or 100000?
Hardcoded External URLs and Log Levels
API endpoints embedded in code require rebuilds for endpoint changes. Log levels baked into Docker images force volume mounts or image rebuilds just to enable DEBUG.
Key takeaways:
- Externalize all settings—and validate them rigorously at startup.
- Enforce one consistent naming convention across HOCON and environment variables.
- Document every parameter: type, valid range, default, and business impact.
- Prefer fail-fast over silent fallbacks.
- Manage feature flags with lifecycle discipline: owner, purpose, and sunset date.
— Editorial Team
No comments yet.