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
FormatStrengthCost
JSONUniversally supported, unambiguousNo comments, verbose
YAMLComments, anchors, reads wellIndentation is meaningful, large implicit type surface
TOMLExplicit types, sections, commentsAwkward for deeply nested or repeated structures
JSONCJSON plus commentsNot JSON; needs a tolerant parser
INISimple and obviousAlmost 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 007 is 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))
PY

Binary formats: size and speed

FormatSchemaSize vs JSONHuman-readable
MessagePackNone~30% smallerNo
CBOROptional~30% smallerNo
ProtobufRequired, compiledMuch smallerNo
AvroRequired, with a writer schemaVery smallNo
JSON + gzipNoneOften smaller than MessagePackYes, 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
  1. Measure before switching. Compressed JSON is frequently as small as a binary format, and it needs no new tooling.
  2. 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.
  3. 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.
  4. Never use a binary format for data a human will read: configuration, fixtures and API responses that people debug by hand.
  5. 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.

Reading and inspecting JSON from the command line JSON in databases and storage

Last refreshed 2026-09-18.