JSON ↔ MessagePack
MessagePack is JSON's shape without JSON's punctuation: the same objects, arrays, strings and numbers, written as bytes. Paste JSON to see exactly what it encodes to and how many bytes that saves, or paste the hex your service logged and read it back as JSON.
How to use it
- Paste JSON. The output pane shows the encoded bytes and the status line compares them with the minified JSON.
- Pick the view you need — hex to paste into a test, base64 to put in a config or a header, byte array to paste into source code.
- Download writes the real binary as
data.msgpack, not the hex view of it. - Going the other way, switch Direction to decode and paste hex or base64 — it works out which one you gave it.
What it encodes to
Every JSON type has a direct MessagePack counterpart, and the encoder always picks the shortest representation the spec allows:
- Small integers cost one byte. 0–127 and −1 to −32 are encoded in the type byte itself, which is why an array of small numbers collapses so dramatically.
- Short strings cost one byte plus their UTF-8 length, up to 31 characters. There are no quotes to pay for and nothing to escape — a string full of quotes and backslashes encodes to exactly its own bytes.
- Objects and arrays carry a length prefix instead of brackets and commas, so a five-key object saves the four commas, the five colons and the two braces.
- Non-integer numbers become float64 — eight bytes plus one. Tick float32 where exact to halve that for values that survive the round trip unchanged; anything that would lose precision stays 64-bit.
- true, false and null are one byte each.
When it is not smaller
Often enough that it is worth checking rather than assuming. A short document can grow: a three-character string costs one prefix byte where JSON spends two quotes, but a 40-character string costs two prefix bytes and JSON still spends two quotes. A document dominated by long text barely moves, because the text is the same bytes either way. The saving comes from structure — many small objects, many small numbers, deep nesting — which is exactly the shape of the API payloads and telemetry that people reach for MessagePack for.
And compression changes the argument entirely. Gzip is very good at repeated key names, which is where MessagePack's advantage mostly lies, so gzipped JSON and gzipped MessagePack are usually much closer than the raw sizes suggest. The size analyser prints all of them side by side — raw, minified, gzipped, and the measured MessagePack — before you commit to changing a format.
Decoding
Paste hex (with or without 0x, spaces or commas) or base64. Everything the spec
defines is understood, including the types JSON has no equivalent for:
- Binary (
bin 8/16/32) comes back as a byte array, since JSON has nowhere to put raw bytes. - Timestamps (extension type −1, all three widths) come back as ISO 8601 strings — that is what almost every producer means by them.
- Other extension types come back as
{"$ext": type, "data": [...]}rather than being dropped, so you can see what was there. - 64-bit integers beyond ±253 come back as strings, because a JavaScript number cannot hold them. Big numbers in JSON is the tool for that problem in general.
If there are bytes left after the first complete value — which is what a stream of concatenated messages looks like — the status line says how many were ignored rather than pretending the input was one message.
FAQ
Is a library being loaded for this?
No. The codec is written out in the page's script, both directions. Nothing is fetched and nothing is uploaded, which also means it keeps working with the network off.
Is the encoding canonical?
It is deterministic — the same input always gives the same bytes, always in the shortest form the spec allows, with object keys in their original order. MessagePack itself defines no canonical form, so a different encoder may produce different (equally valid) bytes, most often by using a wider integer type than it needs. If you need a canonical form for hashing, RFC 8785 canonical JSON is the specified way to get one.
What about CBOR?
Not here. CBOR (RFC 8949) is a near relative with a different byte layout and its own tag registry; the two are not interchangeable, so a CBOR payload pasted into the decoder will either fail or produce nonsense.
Why does my object come back with keys in a different order?
It should not — the decoder preserves the order the bytes were in. What does change: a non-string map key, which MessagePack allows and JSON does not, comes back as the JSON text of that key so the document stays valid.