JSON vs Protobuf

Runs in browser

Compare payload efficiency across formats and compression algorithms

Compression Algorithm

Presets

Message Schema

Define your data structure
#1
#2
#3

Size Analysis none

JSON (Rest) 44 B
Protobuf (gRPC) 10 B
FlatBuffers (Est.) 42 B
Thrift Compact (Est.) 11 B

How to Use

Define fields or use presets to compare formats.

You will see:

  • Byte-level Protobuf Analysis
  • JSON (Minified) vs Binary Sizes
  • Compression wins (Gzip/Brotli)
REST (JSON) Minified (No whitespace)
57 B 44 B
{"id":123,"username":"jdoe","isActive":true}
10 B
08
7B
12
04
6A
64
6F
65
18
01
Hover over the hex bytes to analyze the structure

About JSON vs Protobuf

JSON vs Protobuf is an interactive simulator designed to demonstrate the efficiency differences between two popular data serialization formats. By visualizing byte-level payloads, developers can understand why Protocol Buffers (often used with gRPC) outperform JSON (typically used with REST) in high-throughput systems.

REST vs gRPC: The Core Differences

JSON (REST)

  • Text Based: Numbers like "12345" take 5 bytes (ASCII).
  • Verbose: Field names are repeated in every message.
  • Compression Friendly: Text formats compress very well with Gzip/Brotli.

Protobuf (gRPC)

  • Binary Efficient: Varints and binary packing save space significantly.
  • Schema Driven: No field names in payload.

Under the Hood: Formats & Analysis

A technical breakdown of encoding overheads, wire formats, and trade-offs.

1. What "size in transit" actually consists of

For both formats, the transmitted size is:

payload = data + encoding overhead + framing + (optional) compression

Ignoring transport framing (HTTP/2, gRPC) and compression, the core difference is encoding overhead.

2. Protobuf wire size characteristics

Protobuf is a tagged, varint-encoded, field-oriented format. Each field encodes:

  • field_key = (field_number << 3) | wire_type → varint
  • field_value = encoded depending on type

Overhead Sources

  • Field number + wire type: 1–2 bytes (varint) per field.
  • Length prefix: 1–5 bytes (for strings, bytes, submessages).
  • Varint encoding: Small values = 1 byte, large values = more.

Example: {id: 150, name: "Bob"}

Field 1 key 1 byte id=150 (varint) 2 bytes Field 2 key 1 byte len("Bob") 1 byte "Bob" 3 bytes
Total 8 bytes

3. FlatBuffers wire size characteristics

FlatBuffers is a position-based, table-oriented binary format. It relies on offsets instead of field tags and uses one vtable per object.

Overhead Sources

  • VTable: 4 + 2×field_count bytes.
  • Offsets (pointers): 4 bytes per reference.
  • Alignment padding: 0–3 bytes per field depending on layout.
  • No per-field tags (saves space vs Protobuf).

Example: {id: 150, name: "Bob"}

Root table offset 4 bytes VTable 8 bytes id (uint32) 4 bytes name offset 4 bytes "Bob" + null 4 bytes Alignment ~0-2 bytes
Total ~24-26 bytes

4. Apache Thrift (Compact Protocol)

Originally from Facebook, Thrift is similar to Protobuf but supports a wider range of languages and server implementations. The Compact Protocol is highly efficient.

Wire Characteristics

  • Field Delta: Instead of full Field IDs, it stores the difference from the previous field ID. This allows packing the Field Type (4 bits) and Delta (4 bits) into a SINGLE byte.
  • ZigZag Varints: Like Protobuf, it uses Varints for integers, but defaults to ZigZag encoding for signed ints.
  • Stop Field: Structs end with a 0x00 byte (Stop Field), whereas Protobuf relies on the stream length or length-delimiters.

5. Apache Avro

Avro is unique because the schema is NOT included in the payload (usually). It assumes the reader already has the exact schema (e.g. from a Schema Registry).

Why it's often the smallest

  • No Field Tags: Since the schema is known, Avro simply writes values in order. It does not write field IDs or types.
  • Example: {id: 100, val: 5} → Just the bytes for 100 and 5. Zero overhead for keys.
  • Trade-off: You MUST have the schema to read even a single byte. You cannot "skip" fields without the schema.

6. Size Comparison Summary

Scenario Protobuf FlatBuffers Thrift (Compact) Avro
Small messages Tiny Larger (overhead) Tiny Smallest (No tags)
Access Speed Parsing Req. Instant (O(1)) Parsing Req. Parsing Req.
Schema Evolution Excellent Good (VTable) Good Complex (Registry)

7. Why FlatBuffers is often larger

It trades bandwidth for CPU (Zero-copy deserialization). Structurally heavier due to VTables, 32-bit offsets, and alignment padding.

8. When FlatBuffers can be smaller

When you have large, dense arrays of primitive types (like vectors of floats in games/ML), avoiding varint decoding allows `memcpy` speed and comparable size.

9. Compression Anomalies: Why Gzip Increases Size?

If you select the User Profile preset and toggle Gzip, you might see the size increase (e.g., 34 bytes → 50+ bytes).

The Fixed Overhead Trap

  • Header: Gzip always writes a 10-18 byte header (Magic number, flags, OS ID).
  • Footer: It appends an 8-byte checksum (CRC32) and original size.
  • Dictionary: For tiny payloads, there are no repeated strings to compress, so you pay the overhead cost without any savings.

Solution: Use Brotli (which has a pre-shared static dictionary) or only compress payloads >150 bytes. Try the Complex Event preset to see Gzip actually work!

10. Compression & Practical Conclusion

With compression (Gzip/Brotli), Protobuf/Thrift usually compress better than FlatBuffers/Avro because field tags create predictable patterns, whereas FlatBuffers offsets vary with message size.

For Microservices? Protobuf (gRPC) or Thrift
For Big Data Storage? Avro (Parquet is based on it)
For Games/real-time? FlatBuffers (Zero copy)