A running program holds a graph of objects in memory. The network moves a flat stream of bytes. Serialization is the bridge — and every choice you make there is a tradeoff.
User object with pointers, hash maps, and
language-specific layout. Process B — maybe another language, another machine, another CPU
architecture — needs "the same" user.
User class.
Serialization (a.k.a. marshalling) flattens the in-memory object into a portable byte sequence. Deserialization (unmarshalling) rebuilds an equivalent object on the far side. The byte sequence is the wire format; the class is the runtime representation.
The single most useful mental model: the bytes on the wire are a different thing from the object in your code, and a format is a contract about the bytes, not about your classes.
{ "name": "Bob", "id": 150, "admin": true }
Human-readable, debuggable with curl and your eyes, trivially logged. But every number is
spelled out in ASCII, every key is repeated in full on every record, and the parser must scan for
quotes, braces, and escapes.
0A 03 42 6F 62 10 96 01 18 01
Compact and fast to parse — a number is a few bytes, not a string of digits — but opaque without the schema or a decoder. You trade eyeballs for bytes and CPU.
| Text | Binary | |
|---|---|---|
| Readable by humans | ✅ | ❌ |
| Size on the wire | Large | Small |
| Parse cost | Higher | Lower |
| Debug with plain tools | ✅ | Needs decoder |
The second axis is orthogonal: does the reader need an out-of-band description of the data?
.proto,
.avsc) defines the fields. The wire bytes carry only compact numeric tags — or, with Avro,
no tags at all. Smaller and faster, but the reader must have the schema.
Different formats pick different corners of the same triangle. Know which corner you need:
| Priority | Reach for | Because |
|---|---|---|
| Debuggability / public API | JSON | Everyone can read and generate it |
| Small, fast internal RPC | Protobuf | Numeric tags, varints, codegen |
| Schema-evolving data lake | Avro | Schema stored with the data, no tags on the wire |
| Read without parsing | FlatBuffers | Zero-copy access to fields in place |