Skip to content
Guides

7 JSON Config File Mistakes That Break Production Deployments

·9 min read
7 JSON Config File Mistakes That Break Production Deployments - Guides guide from JSON Prettifier

Quick answer: Reliable JSON configuration needs more than valid syntax. Use the parser your runtime actually supports, keep secrets outside committed files, minimize environment-specific copies, preserve value types and units, define merge precedence, validate the final effective configuration, and fail safely. Test the same startup path that production uses before routing traffic.

A configuration change can ship without touching application code and still alter databases, timeouts, feature flags, or external endpoints. That makes config review operational work, not a formatting chore. These seven mistakes explain why a file that looks harmless in a pull request can behave differently after deployment.

Inspect a sample configuration in the JSON Viewer and use JSON Compare to review the values that changed between versions.

If your application saves configuration at runtime, apply the six JSON file write checks as well. Correct settings can still disappear when concurrent writers replace snapshots computed from the same old file.

1. Are you writing JSONC or JSON5 for a strict JSON parser?

Standard JSON rejects comments, trailing commas, single-quoted strings, and unquoted property names. JSONC and JSON5 deliberately accept some of those features, but only when the consuming tool uses the matching parser. Confirm the exact parser used in production instead of assuming that editor highlighting or a successful local tool proves compatibility.

This file is invalid JSON even though several editors display it comfortably:

{
  // Retry failed requests twice
  "retries": 2,
}

A strict JSON.parse() call rejects both the comment and trailing comma. A JSONC-aware tool may accept both, while JSON5 accepts a wider set of JavaScript-like syntax. Renaming a file does not change the parser; the application must explicitly support that format.

The Google JSON Style Guide says comments should not be included in JSON objects. For the normative grammar, RFC 8259 defines JSON values and permitted whitespace without a comment production.

When a tool documents JSONC, name the file clearly and keep that parser in the execution path. If another service consumes the same artifact, convert it to strict JSON during the build and validate the generated output. Never remove comments with a regular expression; URLs and strings can contain the same slash sequences.

Our comments in JSON guide compares documented alternatives. Use JSON Prettifier for strict JSON syntax, not as proof that a JSONC-specific configuration will behave correctly in its target tool.

2. Are secrets committed inside the JSON configuration?

A valid JSON file is not a secure secret store. Configuration copied into Git, build artifacts, container layers, logs, tickets, or backups can persist long after one visible file is deleted. Keep credentials outside ordinary committed JSON, resolve them through an approved deployment mechanism, and rotate any secret that entered version history.

Avoid committing literal credentials:

{
  "database": {
    "host": "db.internal",
    "password": "real-production-password"
  }
}

A committed file can instead hold non-sensitive structure or a reference understood by the loader:

{
  "database": {
    "host": "db.internal",
    "passwordSecret": "production/orders/database-password"
  }
}

That reference is not a universal standard. Your platform must resolve it securely, authenticate to the secret store, limit access, and avoid printing the result. Document the boundary so nobody later treats the reference as a literal password.

Microsoft's current .NET application-secrets guidance warns against storing sensitive values in source code or configuration. It also notes that environment variables are commonly plain text and can be exposed if a machine or process is compromised. They are a delivery mechanism, not automatic encryption.

Add secret scanning before merge and review generated deployment manifests, not only source files. Our JSON redaction guide covers safer diagnostic copies, while the JSON security checklist addresses the wider trust boundary.

3. Do you maintain complete JSON copies for every environment?

Full configuration copies for development, staging, and production drift because most values are repeated but edited independently. Keep a small, non-secret base plus minimal environment overrides when your platform supports layering. Define ownership and precedence, and generate every environment's effective configuration in tests so a missing update cannot hide in an untouched copy.

Three 200-line files that differ in six places create a review problem. A security setting can change in the intended base but stay stale in one environment. Copying production config into staging also encourages credentials and endpoints to cross boundaries.

A more reviewable layout is:

config/
  base.json
  development.json
  staging.json
  production.json
  config.schema.json

Small override files should contain deliberate differences. That design still needs an explicit merge rule. Does an absent property inherit? Does null erase a value? Do arrays replace, concatenate, or merge by index? A generic deep-merge library can choose behavior appropriate for user-interface state but dangerous for allowlists or ordered middleware.

The Twelve-Factor App configuration principle recommends separating deploy-varying configuration from code and keeping environment controls independently manageable. Its environment-variable approach is one model, not a requirement that every setting become an untyped string. Structured non-secret defaults can remain in JSON when precedence and typing are clear.

Use one loader module instead of scattered reads. It should assemble sources once, expose a typed effective configuration, and record which non-secret source won for each setting. Never log the full merged object.

4. Are strings, numbers, booleans, and units unambiguous?

JSON preserves basic value types, but deployment overrides often arrive as strings. The text "false" is truthy in many programming languages, and "30" does not reveal whether a timeout means milliseconds or seconds. Define each setting's type, range, enum, and unit, then reject ambiguous or out-of-range values before startup completes.

These documents are both valid JSON, but they do not express the same contract:

{
  "featureEnabled": false,
  "requestTimeoutMs": 30000,
  "retryCount": 3
}
{
  "featureEnabled": "false",
  "requestTimeoutMs": "30",
  "retryCount": -1
}

A permissive coercion layer can make the second appear to work until another runtime, validator, or deployment system interprets it differently.

Use names such as timeoutMs, cacheTtlSeconds, and maxUploadBytes when numeric units matter. Put realistic minimum and maximum values in a JSON Schema. Enumerate modes rather than accepting arbitrary strings. Reject unknown keys when typos are dangerous, while keeping documented extension points where forward compatibility matters.

Our JSON Schema guide covers types and constraints. The guide to eight schema validation mistakes explains why required, format, and default can surprise developers. Test the loader too; a correct schema cannot prevent later code from coercing values.

5. Do you validate source files but skip the effective configuration?

Validating base.json and production.json separately does not prove their merged result is usable. An override can replace a nested object, change a value's type, or leave a secret reference unresolved. Assemble configuration exactly as production does, then validate that effective object before any server, queue worker, or scheduled job begins work.

Suppose the base file contains:

{
  "http": {
    "port": 8080,
    "timeoutMs": 5000
  }
}

The production override contains:

{
  "http": {
    "timeoutMs": 15000
  }
}

A shallow merge replaces the entire http object and loses port; a recursive merge preserves it. Neither behavior is universal. The loader's documented contract decides. The mistake is checking two valid fragments without inspecting what the application receives.

A practical preflight sequence is:

  1. Parse each source with its real parser.
  2. Apply sources in documented precedence order.
  3. Resolve approved secret references without logging values.
  4. Validate the effective object against the intended schema draft.
  5. Run semantic checks the schema cannot express cleanly.
  6. Print a redacted summary and exit before starting work when validation fails.

The official JSON Schema getting-started guide demonstrates object constraints. Store passing and failing fixtures beside the schema, including one fixture per environment. Syntax, structure, and operational reachability remain separate checks.

6. Does the application silently continue with unsafe fallback values?

A missing or malformed critical setting should not silently activate a broad permission, public bind address, disabled TLS check, or unlimited timeout. Classify settings by risk, choose explicit safe defaults only where they are genuinely safe, and stop startup with a redacted error when the application cannot establish a trustworthy effective configuration.

Defaults help local development, but they become dangerous when they hide deployment mistakes. Consider ALLOWED_ORIGINS. An empty value might mean deny all, allow all, or use a built-in list. If the loader guesses, a typo in an environment variable can silently change a security boundary.

Write absence behavior into tests:

Setting typeSafer absence behaviorExample
Security boundaryFail startup or deny by defaultAllowed origins
Required dependencyFail startupDatabase endpoint
Performance tuningUse bounded documented defaultPool size
Optional featureDisable explicitlyExperimental exporter
SecretFail without revealing its valueSigning key

An error can identify the setting path, expected source, and remediation without printing a credential. Exit with a nonzero status so the deployment system marks the instance unhealthy.

For broad background, Wikipedia's configuration-file overview describes the pattern across platforms. It is not the authority for your application's fallback rules. Those rules belong in your schema, loader tests, runbook, and deployment policy.

7. Can you prove the new configuration works and can be rolled back?

A syntactically valid, schema-valid configuration can still point to an unreachable service, incompatible region, expired certificate, or wrong tenant. Test high-impact settings through a dry run or narrow deployment, observe startup and dependency health, retain the last known-good version, and make rollback independent of the broken configuration path.

Begin with checks that do not perform destructive work: resolve DNS, establish authenticated connections, verify required topics or buckets exist, and confirm that the application can read its non-secret identity. Apply timeouts so a bad endpoint cannot stall deployment indefinitely.

Version config changes with code when they must ship together. If configuration is delivered separately, record its version or digest in deployment metadata. During an incident, an operator must be able to answer: which effective configuration is this instance using?

A safe rollout sequence is:

  1. Build and validate every environment's effective configuration.
  2. Scan committed and generated artifacts for secrets.
  3. Run the application's preflight command.
  4. Deploy to a limited target.
  5. Check health, dependency errors, and redacted source diagnostics.
  6. Expand gradually when the signals remain healthy.
  7. Restore the known-good version if acceptance checks fail.

Do not claim success because the process started. A worker can boot without permission to its queue, and an API can report healthy while its payment endpoint targets a test account. Define acceptance checks around the behavior controlled by the changed setting.

These seven mistakes form one review path: parse the intended format, separate secrets, minimize duplication, preserve types and units, validate the effective result, fail safely, and prove the rollout. A short JSON file deserves the same evidence as a code change when it controls production behavior.

If the source configuration is YAML, add the YAML-to-JSON conversion checks before validating the effective JSON contract. A successful conversion can still change types, root shape, or values that the application depends on.

Frequently Asked Questions

Is JSON a good format for configuration files?
JSON works well for machine-read configuration that benefits from strict parsing, broad library support, and JSON Schema validation. It is less comfortable for frequently hand-edited files because standard JSON has no comments, trailing commas, variables, or native secret references. Choose the format based on the actual consumer.
Can a JSON config file contain comments?
Standard JSON cannot contain comments. Some tools accept JSONC or JSON5, but that support belongs to the specific parser, not to JSON itself. Use the extension and parser documented by the consuming tool. A file that works in an editor can still fail in a production process using JSON.parse.
Should API keys be stored in a JSON config file?
Do not commit API keys, passwords, private keys, or production connection credentials in ordinary JSON configuration. Keep non-secret settings in version control and resolve secrets from an approved secret manager or deployment mechanism. Environment variables can help, but they also require access control because process environments are not inherently encrypted.
How should environment-specific JSON config files be merged?
Define one deterministic merge contract and test it. State whether nested objects merge recursively, arrays replace or concatenate, and null deletes or overrides a value. Validate the final effective configuration after all files, environment variables, and secret references are applied. Avoid relying on a library's undocumented default merge behavior.
When should an application validate its JSON configuration?
Validate configuration during startup or a dedicated preflight step before accepting traffic or starting background work. Validate both JSON syntax and application constraints, then report safe, actionable errors without exposing secrets. Run the same validation in continuous integration for every supported environment and again after deployment-specific overrides are resolved.

Check your JSON config syntax first

Format and validate a non-sensitive configuration sample before testing its schema, overrides, and production startup behavior.

Open JSON Prettifier