jsonconfigdevopsbest-practices

JSON Configuration Files: Best Practices & Patterns

·8 min read·Advanced

JSON as configuration

From package.json to tsconfig.json to cloud deployment manifests, JSON is everywhere as a configuration format. It is universal and tool-friendly — but it also has sharp edges (no comments, easy to typo) that bite teams who treat config casually. Here is how to do it well.

Structure for clarity

Group related settings into nested objects rather than a flat soup of keys:

json
{
  "server": { "port": 8080, "host": "0.0.0.0" },
  "database": { "url": "postgres://...", "poolSize": 10 },
  "features": { "betaSearch": false, "newCheckout": true }
}

Nesting communicates intent and makes it obvious which subsystem a setting belongs to.

Validate config with a JSON Schema

Config errors are deploy-breaking and often discovered too late. Define a JSON Schema and validate at startup so a typo fails fast with a clear message instead of a mysterious runtime crash:

json
{
  "type": "object",
  "properties": {
    "server": {
      "type": "object",
      "properties": {
        "port": { "type": "integer", "minimum": 1, "maximum": 65535 }
      },
      "required": ["port"]
    }
  },
  "required": ["server"]
}

A schema also powers editor autocomplete and inline error highlighting via the $schema key — many editors read it automatically.

The "no comments" problem

Standard JSON forbids comments, which is painful for config you want to annotate. Options:

  • `$schema` and self-describing keys. Make keys clear enough that comments are unnecessary.
  • JSONC / JSON5. Supersets that allow comments and trailing commas (tsconfig.json is JSONC). Use only where your tooling supports them.
  • YAML or TOML. If you need rich comments, these formats are designed for it — convert to JSON at build time if your app expects JSON.

Never commit secrets

Configuration files live in version control; secrets must not. Keep credentials out of JSON config and load them from environment variables or a secrets manager. A safe pattern is a config file with placeholders and an .env for the real values:

json
{ "database": { "url": "${DATABASE_URL}" } }

Environment-specific config

Avoid one giant file with every environment inline. Common approaches:

  • A base config plus per-environment overrides merged at load time (config.json + config.production.json).
  • Environment variables for anything that differs between deploys.
  • A single schema validating all of them so every environment stays consistent.

Best practices checklist

  • Nest related settings; avoid deep nesting beyond three or four levels.
  • Validate against a JSON Schema at startup.
  • Reference the schema with $schema for editor support.
  • Keep secrets in env vars, never in committed JSON.
  • Use consistent key casing (pick camelCase or snake_case and stick to it).
  • Document non-obvious settings — in a README if the format forbids comments.

Frequently asked questions

Standard JSON cannot. Use JSONC/JSON5 if your tool supports it, switch to YAML/TOML, or rely on self-explanatory keys plus external docs.

Yes — validate at startup against a JSON Schema so misconfigurations fail immediately with a clear error rather than deep in production.

Use a base file with per-environment overrides and environment variables for secrets, all validated by one shared schema.

Try JSON Schema Validator

Validate your config file against a JSON Schema before deploying.