Back to the map

Module 04 · API fundamentals · Lesson 7 of 15

Data formats: JSON, Protobuf, Avro and friends

The wire format shapes size, speed, tooling and how safely you can evolve a schema. JSON for the edge, binary schemas inside, and the rules that keep either from breaking consumers.

IntroShould-knowJunior 9 min Updated Nov 2026

Why it matters

Every byte on the wire is paid for in bandwidth, parsing time and storage, and every field name is a promise to whoever reads it. The format you pick decides whether a message is readable in a log, how much smaller it can get, how fast a service can parse ten thousand of them a second, and what happens when you add a field next month. The choice is rarely dramatic, but the wrong one in the wrong place (text in a hot internal path, an untyped blob in a long-lived event stream) shows up as cost and incidents later.

The idea

A serialization format turns in-memory structures into bytes and back. The axes that matter are human readability, size, parse speed, whether a schema is required, and how the format handles evolution.

 JSONProtocol BuffersAvroMessagePack / CBOR
ReadableYesNoNoNo
SchemaOptional (JSON Schema, OpenAPI)Required (.proto), compiledRequired, usually shipped with the data or via a registryNone (schemaless binary JSON)
SizeLargest: keys repeated in every messageSmall: field numbers, varintsSmallest: no field tags, schema known to both sidesSmaller than JSON, keys still present
SpeedSlowestFast, generated codeFastFast
EvolutionAdd fields freely; no enforcementField numbers; add optional, never reuse numbersReader and writer schemas resolved; defaults requiredSame as JSON, unenforced
Home turfPublic REST APIs, browsers, configsgRPC, service-to-serviceKafka events, data lakesDrop-in JSON replacement where size matters
JSON ~60 Bid, name, pro as text keysProtobuf ~10 B08 2A 12 03 41 64 61 18 01Avro ~7 B54 06 41 64 61 01 (+schema id)
The same record in three formats. JSON spends most bytes on field names; Protobuf replaces them with numbers; Avro omits them because both sides know the schema.

Schema evolution rules

Whatever the format, the same discipline applies. Add fields as optional with sensible defaults. Never remove a field that any reader still expects; mark it deprecated and stop writing it. Never change a field's type or meaning; add a new field instead. In Protobuf, never reuse a field number, because old data encoded with it will be misread. In Avro, readers use their own schema plus the writer's, so every new field needs a default. A schema registry (common with Kafka) stores versions, checks compatibility on publish, and lets consumers fetch the schema by id instead of shipping it with every message.

Where each lives in a real system

JSON at the public edge, because browsers and partners parse it with no toolchain and humans read it in logs. Protobuf between services, because gRPC uses it and typed generated clients catch mismatches at compile time. Avro or Protobuf on event streams and in data lakes, where billions of records make per-byte savings matter and schemas must be enforceable over years. Compress JSON (gzip or brotli) before replacing it; compression recovers much of the size gap, and replacing the format mostly buys parse speed and typing.

Trade-offs

Text formats are debuggable and universal and cost size and speed. Binary formats are compact and fast and need schemas, codegen and tooling to inspect. Schemaless binary gets size without typing and without evolution guarantees. The hidden cost of any typed format is organisational: someone must own the schemas and the compatibility checks, or they become a new source of breakage.

In an interview

Say the format per layer with a reason: "JSON over REST at the edge for compatibility; protobuf over gRPC internally for speed and typed contracts; events on Kafka in Avro with a schema registry enforcing backward compatibility." Then the evolution rule: "Add optional fields with defaults, never remove or retype, never reuse a field number."

Check yourself

A team deletes an unused protobuf field numbered 7 and later adds a new field, also numbered 7, with a different type. Old messages are still in a queue. What happens?

Data formats: JSON, Protobuf, Avro and friends · Backplane