One small record encoded five ways falls in a clean ladder — JSON 81 → MessagePack 66 → Protobuf 33 → Avro 32 bytes. Each rung drops a layer of self-description, and 38% of the JSON turns out to be field names, re-sent in every record.
Encode one small record five ways and its size falls in a clean ladder: JSON spells out every field name and value as text; MessagePack is binary but, having no schema, still carries every field name; Protocol Buffers replaces the names with 1-byte field tags because the schema holds the names; Avro drops even the tags, storing bare values in schema order. You will predict the sizes and watch 81 → 66 → 33 → 32 bytes — each rung dropping a layer of self-description, with 38% of the JSON turning out to be field names repeated in every record.
Designing Data-Intensive Applications, 2nd ed. (Kleppmann & Riccomini, 2025), Chapter 5 — Encoding and Evolution, §"Binary encodings" (and §"Protocol Buffers", §"Avro"):
since they don't prescribe a schema, they need to include all the object field names within the encoded data.
The book walks the same record down from JSON through Protobuf to Avro. Here you encode it and measure each rung — and see exactly which bytes each format spends.
The surprise is about what each encoding must carry besides the values. These help; each line notes where it shows up.
uv, with msgpack, fastavro, and Protocol Buffers (grpcio-tools compiling the .proto at runtime + the protobuf runtime) — no Docker. One record: {userName: "Martin", favoriteNumber: 1337, interests: ["daydreaming", "hacking"]}.
The same record, encoded five ways:
(tag, value) pairs, so a 1-byte tag stands in for the field name.We encode the record in each and compare len(bytes). The whole exercise is one script, code/encoding_size_ladder.py.
cd study/ddia/ch05/code
uv run --with msgpack --with fastavro --with grpcio-tools --with protobuf \
python3 encoding_size_ladder.py
Do not read the output yet — make each prediction first.
Predict. The record has three fields. Write down your guess for the encoded size in JSON, MessagePack, Protobuf, and Avro — in bytes. (Most people guess JSON around 80, and then that the binary formats are "maybe half.")
Do. Run the script.
81 → 66 → 33 → 32. MessagePack shaves only ~18% off JSON — because its bytes are still mostly field names, just without the quotes and colons. The big drop is JSON/MessagePack → Protobuf (2×), where a schema lets a 1-byte tag replace each spelled-out name. Avro squeezes out the last byte by dropping the tags too.
Predict. Of JSON's 81 bytes, how many are the field names — the characters userName, favoriteNumber, interests?
38% of the JSON is field names — userName, favoriteNumber, interests — and those characters are re-sent in every single record. That is the overhead a schema removes: send the names once (in the schema), not a billion times (in the data).
Every encoding must store the values; the ladder is about how much else it stores. JSON is self-describing text: to know that 1337 is the favorite number, the bytes literally contain the string "favoriteNumber" next to it, plus quotes, a colon, and commas. MessagePack keeps JSON's data model but swaps the textual syntax for compact binary type/length markers — so it loses the punctuation but, lacking any schema, must still embed every field name. That is why it only trims ~18%: on a small record, the names are most of the bytes.
Protocol Buffers and Avro break that by moving the field names out of the data and into a schema both sides already have. Protobuf tags each field with a small integer, so the wire format is a sequence of (tag, value) pairs and a 1-byte tag replaces an 8-to-14-character name — halving the size. Avro goes further: because the schema also fixes the field order, Avro doesn't even need tags; it writes the values back to back and nothing else, reaching the floor of "just the data." The price of that last byte is steep in a different currency — Avro's bytes are meaningless without the exact writing schema — which the Avro exercise makes concrete.
Sources: DDIA 2e, Ch. 5, §"Binary encodings", §"Protocol Buffers", §"Avro" · the MessagePack, Protobuf, and Avro encoding specs.