← Back to blog
PERFORMANCE7 min read

MessagePack vs JSON: 47% Smaller Payloads for Real-Time Apps

HB
Henco Burger
April 14, 2026

JSON is everywhere. It is human readable, trivially debuggable, and natively understood by every language runtime that matters. For most HTTP APIs it is the obvious default, and the right one. But for real-time systems moving hundreds of thousands of small messages per second, the overhead of text serialization starts to show up in your latency numbers and your bandwidth bill.

MessagePack is the alternative. It is a binary serialization format that encodes the same data structure as JSON but in a more compact binary representation. Same types, same structure, fewer bytes. Here is how they compare and when the difference actually matters.

What MessagePack Actually Is

MessagePack stores data using a compact type-tagged binary layout. Each value is prefixed with a single byte that encodes its type and sometimes part of its value. Small integers, for example, are stored in a single byte. Short strings store the length in the same byte as the type tag. This is fundamentally different from JSON, which must represent every value as a sequence of ASCII characters regardless of the underlying data type.

The format supports the same logical types as JSON: null, boolean, integer, float, string, binary (bytes), array, and map (object). The key difference is that the representation is binary and therefore not human-readable. You need a decoder to inspect MessagePack data, which is a real tradeoff to acknowledge. Debugging raw bytes is harder than reading a JSON string in your terminal.

Side-by-Side: The Same Message in Both Formats

Take a minimal chat message payload with a few fields:

// The logical data
{
  "id": "01906b2e-4f3c-7a1d-8e2b-9f3c4d5e6a7b",
  "room": "general",
  "text": "Hello, world!",
  "ts": 1745827200000,
  "uid": "u_8x2k9"
}
JSON encoding:
{
  "id":"01906b2e-4f3c-7a1d-8e2b-9f3c4d5e6a7b",
  "room":"general","text":"Hello, world!",
  "ts":1745827200000,"uid":"u_8x2k9"
}
Bytes: 113

MessagePack encoding (hex):
85 a2 69 64 d9 24 30 31 39 30 36 62 32 65 2d 34
66 33 63 2d 37 61 31 64 2d 38 65 32 62 2d 39 66
33 63 34 64 35 65 36 61 37 62 a4 72 6f 6f 6d a7
67 65 6e 65 72 61 6c a4 74 65 78 74 ad 48 65 6c
6c 6f 2c 20 77 6f 72 6c 64 21 a2 74 73 cf 00 00
01 96 e3 6e 9e 80 a3 75 69 64 a6 75 5f 38 78 32
6b 39
Bytes: 67

That is a 41% reduction for one message. Now scale that to 10,000 messages per second across a high-traffic chat server, or 100 telemetry readings per second from a fleet of 5,000 IoT devices. The savings are not theoretical.

Where the Savings Come From

The gains come from a few structural differences:

  • No quoting overhead. JSON must quote every string key and string value. MessagePack encodes string length as a prefix byte and stores the string bytes directly. For a map with five keys, that eliminates 10 quotation characters.
  • No key/value separator characters. JSON uses colons and commas as structural delimiters. MessagePack uses a fixed-width map header that encodes the count of entries. No colons, no commas, no whitespace.
  • Compact integer encoding. A 64-bit integer in JSON takes up to 20 ASCII characters. In MessagePack it takes exactly 9 bytes (1 type byte + 8 data bytes) for a 64-bit integer, or as few as 1 byte for small positive integers.
  • Native binary support. This is the one that matters most for IoT and media. JSON has no binary type. To embed binary data in JSON you must Base64-encode it, which inflates the size by approximately 33%. MessagePack has a native binary type. You write raw bytes directly into the payload. No encoding overhead.

Real-World Reduction Numbers

We benchmarked a set of representative payloads across three workload types:

Workload               JSON (bytes)   MsgPack (bytes)   Reduction
---------------------------------------------------------------
Chat message (small)       113             67              41%
Chat message (medium)      287            168              41%
IoT telemetry (10 fields)  312            181              42%
IoT telemetry (binary)     894            421              53%
Dashboard update           1,840        1,024              44%
Presence event              98             58              41%

The 30-50% range cited in benchmarks across the industry holds up consistently. Payloads with binary blobs see even larger reductions because they avoid Base64. Payloads that are mostly long string values see smaller reductions because string content itself does not compress further.

When This Actually Matters

For a low-traffic app sending a few messages per second, the difference between JSON and MessagePack is noise. Choose JSON for the debuggability. The tradeoff changes in a few specific situations.

High-Frequency IoT

A GPS tracker sending position updates 10 times per second is generating 600 messages per minute per device. At 10,000 devices that is 6 million messages per minute. A 40% payload reduction translates directly into server costs, CDN egress fees, and mobile data usage for devices on cellular connections.

Chat at Scale

A busy chat platform might see 50,000 messages per minute across all rooms. Each message is fanned out to multiple subscribers. The total bytes transferred is the message size multiplied by the number of recipients. At scale, a smaller message size has a multiplier effect on your infrastructure cost.

Mobile Clients on Limited Data

Mobile apps on 3G or metered data plans benefit directly from smaller payloads. Faster serialization (MessagePack is typically 2-4x faster to encode and decode than JSON in most runtimes) also reduces CPU time on constrained devices, which means better battery life.

The Debuggability Tradeoff

The biggest practical downside of MessagePack is that you cannot read a raw message in a network inspector without a decoder. This is a real cost during development. The mitigation is to use JSON in development and switch to MessagePack in production, or to build a small decoder step into your debugging tooling. Most serious real-time systems end up doing this anyway because their debugging tooling ends up outliving any specific wire format decision.

How NoLag Uses MessagePack

MessagePack is the wire format for all NoLag WebSocket traffic. Every message published to a topic, every presence event, every typing indicator, every acknowledgment travels as a MessagePack-encoded binary frame over the WebSocket connection.

The SDK handles encoding and decoding transparently. You pass a plain JavaScript object to room.sendMessage() and receive a plain JavaScript object in your onMessage() handler. The binary serialization is invisible to application code.

The combination of WebSocket framing (which has a 2-14 byte overhead per message vs hundreds of bytes for HTTP headers) and MessagePack encoding gives NoLag a per-message overhead that is close to the theoretical minimum for a framed binary transport. For customers running IoT workloads or high-frequency trading dashboards, this is measurable in their cloud bills within the first month of migration from JSON-over-HTTP polling.