DevToys Web Pro iconDevToys Web ProBlog
Ohodnoťte nás:
Vyskúšajte rozšírenie prehliadača:
← Back to Blog

CBOR vs MessagePack: Binary JSON Formats Explained

8 min read

JSON is ubiquitous, but it carries overhead: every key is repeated as a string, numbers are text, and binary data must be base64-encoded before it fits inside a JSON string. CBOR and MessagePack are two popular binary alternatives that shrink payloads and parse faster while staying schemaless like JSON. Use the CBOR / MessagePack converter to encode and decode both formats directly in your browser as you follow along.

Why Binary Serialization?

Three concrete advantages drive adoption of binary serialization over plain JSON:

  • Smaller payloads. Integer values like 300 take 3 bytes as JSON text but only 2 bytes in CBOR or MessagePack (one type byte + one value byte for values up to 255, two for values up to 65535). Maps and arrays drop their surrounding brace and bracket characters entirely.
  • Faster parsing. A JSON parser must tokenize text character by character and handle Unicode escapes. A binary decoder reads a type byte then jumps directly to the value — the structure is machine-native rather than human-native.
  • Native binary and byte strings. Raw bytes (images, cryptographic keys, file chunks) serialize without base64 encoding. This alone can cut payload size by ~33% for binary-heavy data and avoids the encode/decode round-trip on both ends.

The trade-off is debuggability. A JSON payload is readable in a terminal or browser DevTools with zero tooling. A CBOR or MessagePack payload looks like random bytes until decoded. This is why a browser-based decoder matters most during development and incident investigation.

CBOR — Concise Binary Object Representation

CBOR is defined by RFC 8949 (updated from RFC 7049). Its design goal is to be self-describing: a decoder requires no schema to reconstruct the full value tree, including type information. This makes CBOR the format of choice in security and IoT protocols.

  • WebAuthn / FIDO2 and COSE. The W3C WebAuthn spec and the COSE (CBOR Object Signing and Encryption) standard (RFC 8152) mandate CBOR for authenticator data, attestation objects, and signed structures. When you debug a WebAuthn registration response, the attestationObject field is base64url (CBOR (base64url(...))).
  • IoT and CoAP. The Constrained Application Protocol (CoAP, RFC 7252) pairs with CBOR to minimize overhead on microcontrollers and low-bandwidth links. Sensor readings and device telemetry rarely need human-readable text on the wire.
  • Deterministic encoding. RFC 8949 defines a Deterministic Encoding variant where map keys are sorted and the shortest valid encoding is always chosen. This enables reproducible signatures over CBOR structures — critical for COSE and certificate transparency.

MessagePack — Compact and Widely Adopted

MessagePack predates CBOR and takes a slightly different philosophy: maximum compactness over strict self-description. It has no formal RFC — the spec lives at msgpack.org — but it is stable and has libraries in every major language.

  • Redis. Redis uses MessagePack internally for RDB snapshots and in several modules. The OBJECT ENCODING command sometimes exposes msgpack-encoded objects. Client libraries like ioredis can optionally serialize/deserialize values as MessagePack to avoid JSON overhead.
  • Game development. Multiplayer game state updates are latency-sensitive and high-frequency. MessagePack is popular in game backends (Unity, Unreal, custom C++ servers) because the serializer/deserializer is fast and the format is compact enough to fit within UDP packet budgets.
  • msgpack-rpc. A lightweight RPC protocol built on MessagePack that predates gRPC. Still found in editors (Neovim uses it for its remote plugin API) and some embedded systems toolchains.

Wire Format: The First Byte

Both formats encode type and length information in the first byte of each value. Understanding this byte is the key to reading a hex dump manually.

CBOR major types. The high 3 bits of the initial byte identify the major type; the low 5 bits are additional info (the value itself for small integers, or the length/continuation indicator for larger ones):

Major TypeBitsMeaningExample
0000Unsigned integer0x01 = 1
1001Negative integer0x20 = ‑1
2010Byte string0x43 ab cd ef = 3 bytes
3011Text string (UTF-8)0x63 66 6f 6f = "foo"
4100Array0x82 = 2-item array
5101Map0xa1 = 1-pair map
6110Tagged item0xc1 = epoch timestamp tag
7111Float / simple values0xf5 = true

Example: mapping a small JSON object to CBOR bytes. Consider the object {"n": 42}. In CBOR:

JSON:  {"n": 42}   (10 bytes as UTF-8)
CBOR:  a1 61 6e 18 2a  (5 bytes)

a1       = major type 5 (map), 1 pair
61 6e    = major type 3 (text string), length 1, UTF-8 byte 0x6e = "n"
18 2a    = major type 0 (unsigned int), additional info 24 = 1-byte follows, 0x2a = 42

MessagePack uses a similar first-byte encoding but with different bit layouts. A fixmap uses the high nibble 0x8_, a fixstr uses 0xa_, and small positive integers are encoded directly as a single byte (0x000x7f). The same object in MessagePack:

JSON:     {"n": 42}   (10 bytes)
MsgPack:  81 a1 6e 2a  (4 bytes)

81       = fixmap, 1 pair
a1 6e    = fixstr, length 1, byte 0x6e = "n"
2a       = positive fixint 42

Encoding and Decoding in JavaScript

// CBOR — using the 'cbor-x' library (Node.js / browser)
import { encode, decode } from 'cbor-x';

const obj = { sensor: 'temp', value: 23.5, ts: 1717660800 };
const bytes = encode(obj);
console.log(Buffer.from(bytes).toString('hex'));
// → a3 66 73 65 6e 73 6f 72 64 74 65 6d 70 65 76 61 6c 75 65 f9 ...

const back = decode(bytes);
console.log(back); // { sensor: 'temp', value: 23.5, ts: 1717660800 }
// MessagePack — using 'msgpackr' (Node.js / browser)
import { pack, unpack } from 'msgpackr';

const obj = { sensor: 'temp', value: 23.5, ts: 1717660800 };
const bytes = pack(obj);
console.log(Buffer.from(bytes).toString('hex'));
// → 83 a6 73 65 6e 73 6f 72 a5 76 61 6c 75 65 cb 40 37 80 00 ...

const back = unpack(bytes);
console.log(back); // { sensor: 'temp', value: 23.5, ts: 1717660800 }

Format Comparison

PropertyCBORMessagePackJSONProtobuf
Schema requiredNoNoNoYes (.proto)
Self-describingYesMostlyYesNo
Formal specRFC 8949msgpack.orgRFC 8259Google spec
Native binary/bytesYesYesNo (base64)Yes
Deterministic encodingYes (opt-in)NoNoNo
Typical size vs JSON40–60% smaller40–60% smallerbaseline50–80% smaller
Common use casesWebAuthn, CoAP, COSERedis, game dev, RPCREST APIs, configgRPC, build systems

Unlike Protobuf, which requires a .proto schema file to decode a payload meaningfully, both CBOR and MessagePack are self-describing enough that a generic decoder can reconstruct the full value tree. For schema-driven use cases where maximum compactness and strong typing matter, see the Protobuf decoder and the Protobuf Decoding guide.

When Binary Beats JSON — and When It Doesn't

Binary serialization is the right choice when:

  • Payload size matters at scale. A 50% payload reduction on 10 million API calls per day translates directly to bandwidth cost and mobile data savings.
  • You are sending raw binary fields. Cryptographic signatures, image thumbnails, UUIDs as 16-byte arrays — all become native fields rather than base64 blobs.
  • Parsing speed is a bottleneck. High-frequency time-series data, game state sync at 60 Hz, or IoT telemetry from thousands of devices all benefit from sub-millisecond decode times.
  • A protocol mandates it. WebAuthn, CoAP, and msgpack-rpc leave no choice — the spec defines the wire format.

Stick with JSON when:

  • Debuggability matters most. Public REST APIs, config files, and log entries benefit enormously from being readable without tooling. A curl call returns something a human can read immediately.
  • Browser <> server with no build step. JSON.stringify and JSON.parse are built-in; CBOR and MessagePack require a library bundle.
  • Payloads are tiny. For responses under a few hundred bytes, the overhead difference is negligible and not worth the added dependency.

Decoding an Unknown Binary Payload

When you receive an opaque binary blob — from a WebSocket frame, an HTTP response with Content-Type: application/cbor or Content-Type: application/x-msgpack, or a file on disk — the first step is identifying the format. A few heuristics help:

  • CBOR payloads often start with 0xa_ (map) or 0x8_ (array) for top-level collections; small objects frequently start with 0xbf (indefinite-length map).
  • MessagePack fixmap starts with 0x8_ and fixarray with 0x9_, making the high nibble the first discriminator.
  • If neither heuristic matches, try both decoders. A valid CBOR decode will produce a structured value; a failed decode will produce a parse error.

The CBOR / MessagePack converter tries both formats and shows you the decoded tree, the re-encoded hex, and the byte-level diff. Paste a hex string or upload a binary file to inspect an unknown payload without writing any code.


Whether you are debugging a WebAuthn attestation, inspecting Redis wire traffic, or optimizing a game server payload, CBOR and MessagePack give you compact, schemaless binary encoding without the ceremony of a schema file. Decode and encode both formats instantly with the CBOR / MessagePack converter.