Skip to content

vs MessagePack, CBOR

MessagePack and CBOR are self-describing: a decoder can read a payload without its schema. That is often the right tradeoff, but their plain formats use about 3× as many bytes in these fixtures.

CodecPersonNested event100 events
shorn8434,135
msgpackr shared records10524,993
cbor-x shared records14625,972
@msgpack/msgpack2311511,281
msgpackr plain2512111,881
cbor-x plain2612211,972

shorn is 64% smaller than plain msgpackr for the nested event and 65% smaller for the batch. It is 17% smaller than msgpackr shared records, whose reported steady-state sizes exclude their structure table.

msgpackr shared records and cbor-x record extensions also move field names out of each payload. The difference is how that shared structure is defined and distributed.

shornShared records
Where key names liveyour validation schemaa structure table both ends synchronize
How it reaches the readeryou already deployed the schemaout-of-band state, built as records are seen
On a mismatchDecodeError with fingerprinted()depends on table state
Sizes quotedstandalonesteady-state, table excluded

Both approaches require shared structure outside the payload. With shorn, that structure is the validation schema you already deploy.

FixtureOpshornmsgpackr records
Personenc25.16M10.55M
Persondec67.55M18.96M
Nested eventdec11.45M8.36M
100 eventsdec116.3K88.1K

shorn leads every fixture in both directions, including Unicode-heavy decoding (7.68M vs 3.97M). The nested event and batch used to be shorn’s largest performance gap — shared-record decoders were roughly 2× faster there. Generating a record decoder per object schema closed that gap and reversed it: shorn is now 1.37× faster on the nested event and 1.32× on the batch. See Throughput.

msgpackr records still encode text-heavy payloads faster, but only barely (8.04M vs shorn’s 7.74M on the Unicode fixture) — the one fixture in either direction where shorn does not lead this table.

100,000 repetitive events:

CodecRawGzipBrotli q6
shorn4,231,777924,494603,189
msgpackr records4,995,3391,114,738513,630

shorn is smaller raw and under gzip, but 17% larger under Brotli. Brotli’s larger window compresses repeated metadata particularly well. If you store repetitive Brotli-compressed data, benchmark your own payloads. For the high-entropy fixture, shorn ranks first raw and under gzip, and second under Brotli.

CodecMinifiedGzip
shorn17.57 KB5.39 KB
@msgpack/msgpack21.20 KB5.93 KB
msgpackr27.59 KB10.39 KB
cbor-x29.10 KB10.82 KB

Validation libraries are excluded from every row, and shorn assumes your application already ships one. msgpackr records also start much faster: 1.00 µs compared with shorn’s 52–66 µs.

  • No schema needed to read. A generic tool can inspect any payload.
  • Broad value support. cbor-x handles Date, Map, Set, bigint natively; shorn refuses all four (rich types).
  • Cross-language. Both are standards with implementations everywhere; CBOR is an IETF standard.
  • Streaming. Both support incremental encode and decode.
  • Encode speed on text. msgpackr records still encode the Unicode fixture faster.
  • Startup. msgpackr records are ready in 1.00 µs against shorn’s 52–66 µs.
UseWhen
shornTypeScript both ends, already validating, smallest raw and gzip payloads matter
msgpackrYou need Date/Map/Set natively, cold-start latency dominates, or you cannot guarantee a schema on both ends
@msgpack/msgpackConservative standard MessagePack with broad interop
cbor-xYou need CBOR specifically, usually for standards compliance

The main question is whether both endpoints have the schema. If they do, shorn can omit repeated structure from the payload. If they do not, use a self-describing format such as MessagePack.