Why Config File Format Matters
Configuration files are the interface between your software and the humans who operate it. A poor format choice creates friction: obscure syntax errors, unexpected type coercions, poor diffs in version control, and steep learning curves for new team members. The three dominant text-based config formats each solve the problem differently.
JSON
JSON (JavaScript Object Notation) was designed for data interchange, not human-authored config files. It was later adopted as a config format because of its ubiquity and strict parsing rules.
{
"server": {
"host": "0.0.0.0",
"port": 8080,
"timeout": 30
},
"database": {
"url": "postgres://localhost/myapp",
"pool_size": 10
}
}
Strengths:
- Universal tooling support — every language has a JSON parser
- Strict and unambiguous: no type guessing, no implicit conversions
- Great for machine-generated config (Prettier, ESLint, package.json)
- Excellent diff readability in version control
Weaknesses:
- No comments — a significant pain point for config files
- Verbose syntax (quotes on every key, commas, brackets)
- No multi-line strings without awkward escaping
- Trailing commas are a syntax error (though JSONC fixes this)
Best for: npm/package.json, VS Code settings, language tooling configs, APIs where the consumer is code rather than a person.
YAML
YAML (YAML Ain't Markup Language) was purpose-built for human-readable config. It prioritizes minimal punctuation and natural expression.
server:
host: 0.0.0.0
port: 8080
timeout: 30
database:
url: postgres://localhost/myapp
pool_size: 10
# Comments work natively
feature_flags:
new_dashboard: true
beta_api: false
Strengths:
- Comments supported natively
- Minimal punctuation — no quotes required for most strings
- Multi-line strings with
|(literal) and>(folded) - Anchors and aliases for DRY configs
- Widely used in DevOps (Docker Compose, Kubernetes, GitHub Actions, Ansible)
Weaknesses:
- Indentation-sensitive: a stray space breaks the file
- Type inference can surprise you:
port: 8080is an integer, butversion: 1.10may be parsed as1.1 - Norwegian developer problem:
nois parsed as booleanfalsein YAML 1.1 - Complex features (merge keys, multiple documents) add cognitive load
Best for: Docker Compose, Kubernetes manifests, CI/CD pipelines (GitHub Actions, GitLab CI), Ansible playbooks, Hugo/Jekyll static sites.
TOML
TOML (Tom's Obvious Minimal Language) was created in 2013 by Tom Preston-Werner (GitHub co-founder) specifically to be a config format that is unambiguous, readable, and predictable.
[server]
host = "0.0.0.0"
port = 8080
timeout = 30
[database]
url = "postgres://localhost/myapp"
pool_size = 10
# Comments work natively
[feature_flags]
new_dashboard = true
beta_api = false
Strengths:
- Explicit types: strings require quotes, numbers don't, booleans are
true/false - No indentation-sensitivity: structure is defined by
[section]headers - Comments supported
- First-class date/time types:
2026-05-21,2026-05-21T09:00:00Z - Unambiguous: no surprise type coercions
Weaknesses:
- Less tooling support than JSON or YAML (improving rapidly)
- Arrays of tables have unintuitive syntax
- Not suitable for deeply nested structures
- Less familiar to developers who haven't used Rust or Cargo
Best for: Rust projects (Cargo.toml), Hugo configurations, Python tools (pyproject.toml, poetry), any project that prioritizes config file correctness over ecosystem convention.
Side-by-Side Comparison
| Feature | JSON | YAML | TOML |
|---|---|---|---|
| Comments | ❌ | ✅ | ✅ |
| Indentation-sensitive | ❌ | ✅ | ❌ |
| Multi-line strings | Awkward | ✅ | ✅ |
| Strict types | ✅ | ❌ | ✅ |
| Arrays | ✅ | ✅ | Verbose |
| Dates/times | ❌ | ❌ | ✅ |
| Universal tooling | ✅ | ✅ | Growing |
| DevOps ecosystem | Low | High | Medium |
Which Should You Choose?
Choose JSON when:
- The file is written by tools, not humans (package.json, .eslintrc)
- Strict schema validation is a priority
- You need maximum language/tooling compatibility
Choose YAML when:
- You're working in the Kubernetes, Docker, or GitHub Actions ecosystem
- Your team already uses YAML and consistency matters
- You need inline comments for documentation
Choose TOML when:
- You're building a Rust project (Cargo.toml is standard)
- You want predictable type parsing without surprises
- Your config has many settings that benefit from section headers
Converting Between Formats
If you inherited a project using one format and want to migrate to another:
→ TOML to JSON — Convert TOML configuration to JSON → TOML to YAML — Convert TOML to YAML → YAML to JSON converter — Convert YAML to JSON → YAML to TOML — Convert YAML to TOML → JSON to TOML — Convert JSON to TOML