When to use something else
YAML, TOML, CSV, MessagePack and Protobuf each win somewhere JSON does not - and each has a cost worth naming before you adopt it.
Configuration: YAML and TOML
# YAML: comments, anchors, and significant indentation
defaults: &defaults
retries: 3
timeout_seconds: 30
services:
api:
<<: *defaults
port: 8080
hosts:
- api.example.com
- api.internal# TOML: explicit, typed, and unambiguous about nesting
[service]
name = "api"
port = 8080
[service.limits]
retries = 3
timeout_seconds = 30
enabled = true
released = 2026-09-18 # a real date type, not a string| Format | Strength | Cost |
|---|---|---|
| JSON | Universally supported, unambiguous | No comments, verbose |
| YAML | Comments, anchors, reads well | Indentation is meaningful, large implicit type surface |
| TOML | Explicit types, sections, comments | Awkward for deeply nested or repeated structures |
| JSONC | JSON plus comments | Not JSON; needs a tolerant parser |
| INI | Simple and obvious | Almost no structure, no types, no nesting |
⚠️
YAML's implicit typing is the source of its most famous bugs:
no parses as a boolean false, a version like 1.10 becomes a float, and a value beginning with * is an alias. Quote anything that is meant to be a string, and never build a YAML document by string concatenation.Tabular data: CSV
id,email,plan,created_at
1042,[email protected],annual,2026-01-04
1043,[email protected],monthly,2026-02-11- CSV is smaller, streams line by line, and opens in every spreadsheet - which is often the actual requirement.
- There are no types: everything is a string, and the reader decides whether
007is a number or an identifier. - There is no nesting. A list of line items needs either a second file or an encoded column.
- Quoting rules are only mostly standard; use a real CSV writer rather than joining with commas.
# converting between the two, with the shape made explicit
jq -r '.users[] | [.id, .email, .plan, .created_at] | @csv' users.json > users.csv
# and back, treating every value as text
python - <<'PY'
import csv, json
with open("users.csv") as f:
rows = list(csv.DictReader(f))
print(json.dumps(rows, indent=2))
PYBinary formats: size and speed
| Format | Schema | Size vs JSON | Human-readable |
|---|---|---|---|
| MessagePack | None | ~30% smaller | No |
| CBOR | Optional | ~30% smaller | No |
| Protobuf | Required, compiled | Much smaller | No |
| Avro | Required, with a writer schema | Very small | No |
| JSON + gzip | None | Often smaller than MessagePack | Yes, after decompression |
import { encode, decode } from "@msgpack/msgpack";
const bytes = encode({ id: "ord_9f2c", total_minor: 3998 });
byteLength(bytes); // 40, against 46 for the JSON text
// the real saving is in a large array of similar records
const compact = encode(orders); // repeated keys are the compression win- Measure before switching. Compressed JSON is frequently as small as a binary format, and it needs no new tooling.
- Binary formats trade debuggability for size and speed: a payload is unreadable in a log, a proxy or a terminal, which is a real operational cost.
- Protobuf and Avro earn their complexity when a schema registry and code generation remove more work than they add, and when the same data crosses several services.
- Never use a binary format for data a human will read: configuration, fixtures and API responses that people debug by hand.
- Keep JSON at the edges. Services can speak binary internally while the public interface stays JSON - most of the size saving is between services, not at the boundary.
# the comparison that matters, on your own data
ls -l payload.json
gzip -9 -c payload.json | wc -c
node -e 'const m=require("@msgpack/msgpack"),fs=require("fs");
console.log(m.encode(JSON.parse(fs.readFileSync("payload.json"))).length)'FAQ
Should I use YAML instead of JSON for an API?
No. YAML's implicit types and indentation sensitivity make it unsuitable for machine-generated data, and every consumer would need a YAML parser with the same interpretation of ambiguous values. Use it for files a person edits, and JSON for data that programs exchange.
Is switching to Protobuf worth it?
Only when size or serialisation speed is a measured bottleneck, or when you want a compiled schema across many services. At the boundary of a web API, the debugging cost usually outweighs the saving - compressed JSON is close enough on size.
Related
Reading and inspecting JSON from the command line JSON in databases and storage
Last refreshed 2026-09-18.