JSON Diff: Structural Comparison vs Text Diff for Config and Code Review
How to compare JSON structurally — key order, arrays, nested objects — and when to use JSON diff versus line-based text diff in config and API review workflows.
When to use JSON, YAML, or TOML for app config — conversion pitfalls, trailing commas, multiline strings, and a safe workflow for editing and validating files.
By codefunc
Config files look simple until a silent type coercion ships the wrong port, a trailing comma breaks CI, or a multiline string loses its newlines in conversion. JSON, YAML, and TOML each solve different jobs. Pick the wrong one — or convert carelessly — and you spend hours debugging whitespace. This guide compares the three formats developers actually use and shows how to move between them safely.
Bottom line: JSON for APIs and strict interchange; YAML for human-edited DevOps files when you accept its complexity; TOML for app config with clear nesting. Validate after every conversion. Format messy docs with the YAML Formatter. Use JSON to YAML, YAML to JSON, TOML to JSON, and JSON to TOML as checkpoints — never as a blind rewrite of production config.
| Concern | JSON | YAML | TOML |
|---|---|---|---|
| Human editability | Low–medium | High (until it isn't) | High for flat/nested tables |
| Spec complexity | Small | Large | Medium |
| Comments | No (JSONC / JSON5 variants only) | Yes # |
Yes # |
| Trailing commas | No (strict JSON) | N/A (indentation) | Allowed in arrays/tables per rules |
| Types | string, number, bool, null, array, object | + dates, multiline, anchors | string, int, float, bool, datetime, array, table |
| Best fit | APIs, lock-ish data, tooling I/O | CI, K8s, Ansible | Cargo, many app configs |
JSON is ubiquitous because every language parses it the same way (with minor number/precision caveats).
{
"server": {
"host": "0.0.0.0",
"port": 8080,
"tls": true
},
"features": ["search", "export"]
}
JSON Schema)| Issue | Detail |
|---|---|
| No comments | Teams invent "_comment" keys or switch to JSONC in editors only |
| Trailing commas | {"a":1,} is invalid in strict JSON — breaks many CI validators |
| Numbers | No integers vs floats distinction; large ints lose precision in JS |
| No multiline strings | Newlines must be \n escapes |
If humans edit the file daily and need comments, JSON is often the wrong primary format — generate JSON from something friendlier instead.
YAML 1.1 / 1.2 powers Kubernetes manifests, GitHub Actions, and countless deploy files.
server:
host: 0.0.0.0
port: 8080
tls: true
features:
- search
- export
&ref, *ref) for DRY manifests|, >) for scripts and certs| Pitfall | Example | Safer approach |
|---|---|---|
| Norway problem / bool coercion | country: NO → false in YAML 1.1 |
Quote: "NO"; prefer YAML 1.2 parsers |
| Sexagesimal / version strings | version: 1.10 may become float |
Quote version strings |
| Tabs | Indentation with tabs fails | Spaces only |
| Anchor sprawl | Overrides hide real values | Limit anchors; prefer generators |
| Duplicate keys | Last key wins in many parsers | Lint for duplicates |
Convert YAML to JSON with YAML to JSON to see the actual typed structure your app will receive — especially before you commit a "small" edit.
# Literal — keeps newlines
script: |
npm ci
npm test
# Folded — joins to spaces (mostly)
note: >
This becomes
one long line.
Round-tripping through JSON often loses the distinction between | and > — you get a single string either way. That is fine for machines; painful if you expected to preserve YAML style.
TOML (a minimal, table-oriented config language) is popular in Rust (Cargo.toml), Python tooling, and many static site generators.
[server]
host = "0.0.0.0"
port = 8080
tls = true
features = ["search", "export"]
| Issue | Detail |
|---|---|
| Table vs array-of-tables | [[plugins]] semantics confuse newcomers |
| Dotted keys | server.port = 8080 vs [server] — both valid; pick one style |
| Inline tables | { host = "x", port = 80 } cannot nest arbitrarily in older mental models |
| Conversion to YAML | Key order and table flattening can surprise |
Use TOML to JSON to inspect the nested object form, and JSON to TOML when migrating a JSON config into a human-edited TOML file.
| Situation | Prefer |
|---|---|
| Public HTTP API payloads | JSON |
| Package lock / deterministic machine output | JSON |
| Kubernetes / CI workflows edited by many people | YAML (with linting) |
| Application settings file in a repo | TOML or JSON |
| Need comments + simple nesting, hate YAML surprises | TOML |
Must work in browser JSON.parse with no deps |
JSON |
Hybrid pattern that works well: TOML or YAML for humans → validate → emit JSON for the runtime.
Before and after converting:
| Format | Trailing comma in lists/objects |
|---|---|
| Strict JSON | Invalid |
| JSONC / JSON5 | Often allowed |
| TOML | Allowed in arrays; follow TOML rules for tables |
| YAML | Not comma-delimited — indentation defines structure |
Editor "JSON with Comments" that accepts trailing commas will save a file that JSON.parse and many CI steps reject. Align editor language mode with the real consumer.
Use JSON when machines exchange data, YAML when your ecosystem already standardized on it (and lint aggressively), and TOML when humans own nested app config. Never trust a visual glance after conversion — round-trip through YAML to JSON or TOML to JSON, format with a JSON Formatter, and quote ambiguous scalars. Trailing commas and multiline strings are the usual silent breakages.
How to compare JSON structurally — key order, arrays, nested objects — and when to use JSON diff versus line-based text diff in config and API review workflows.
How to format and inspect XML without breaking namespaces, attributes, or mixed content — plus when to beautify vs minify and how XPath fits the workflow.
How to convert between CSV and JSON safely — quoting, nested objects, type coercion, headers, and a workflow that catches breakage before it hits production.
Find a developer tool