Benchmarks
Operation speed and serialised size versus SQLite’s JSON and JSONB.
Performance benchmarks
Nanoseconds per operation — lower is better.
json/mp and jsonb/mp: ratio relative to msgpack (>1 means msgpack is faster).
Platform: macOS · SQLite 3.53.1
| Operation | msgpack ns/op | json ns/op | jsonb ns/op | json/mp | jsonb/mp |
|---|---|---|---|---|---|
| map build (4 fields) | 408.3 | 1168.3 | 1408.8 | 2.86x | 3.45x |
| array build (8 integers) | 328.9 | 584.9 | 757.7 | 1.78x | 2.30x |
| nested build (map + array) | 782.8 | 647.6 | 1218.1 | 0.83x | 1.56x |
| extract text field ($.name) | 573.9 | 944.6 | 649.3 | 1.65x | 1.13x |
| extract numeric field ($.score) | 577.2 | 1016.6 | 767.3 | 1.76x | 1.33x |
| type check ($.name) | 549.6 | 914.2 | n/a | 1.66x | n/a |
| set field ($.extra = 42) | 818.7 | 1590.7 | 950.1 | 1.94x | 1.16x |
| remove field ($.active) | 865.6 | 1218.0 | 719.8 | 1.41x | 0.83x |
| group_array (1 000 rows) | 88231.7 | 127026.7 | 142550.0 | 1.44x | 1.62x |
| group_object (1 000 rows) | 130031.7 | 184090.0 | 215260.0 | 1.42x | 1.66x |
| each — iterate 4-field map | 2986.1 | 1172.6 | 1004.0 | 0.39x | 0.34x |
| valid check | 536.4 | 812.3 | n/a | 1.51x | n/a |
| from_json (parse JSON text → blob) | 1000.6 | n/a | n/a | n/a | n/a |
| to_json (serialise blob → JSON text) | 1588.2 | n/a | n/a | n/a | n/a |

Serialised-size comparison
Byte sizes for identical logical data encoded as msgpack, JSON (text), and SQLite JSONB (binary). mp/json % and mp/jsonb % show msgpack size as a percentage of the other format — below 100 % means msgpack is more compact.
Platform: macOS · SQLite 3.53.1
| Payload | msgpack (B) | json (B) | jsonb (B) | mp/json % | mp/jsonb % |
|---|---|---|---|---|---|
| null | 1 | 4 | 1 | 25% | 100% |
| true (via from_json) | 1 | 4 | 1 | 25% | 100% |
| false (via from_json) | 1 | 5 | 1 | 20% | 100% |
| integer 0 | 1 | 1 | 2 | 100% | 50% |
| integer 42 | 1 | 2 | 3 | 50% | 33% |
| integer 128 (uint8 boundary) | 2 | 3 | 4 | 67% | 50% |
| integer 65536 (uint32 range) | 5 | 5 | 6 | 100% | 83% |
| integer 1 000 000 000 | 5 | 10 | 11 | 50% | 45% |
| integer -1 | 1 | 2 | 3 | 50% | 33% |
| integer -128 (int8 boundary) | 2 | 4 | 5 | 50% | 40% |
| float 3.14 | 9 | 4 | 5 | 225% | 180% |
| string 2 chars ("hi") | 3 | 4 | 3 | 75% | 100% |
| string 11 chars ("hello world") | 12 | 13 | 12 | 92% | 100% |
| string 31 chars (fixstr max) | 32 | 33 | 33 | 97% | 97% |
| string 32 chars (str8 range) | 34 | 34 | 34 | 100% | 100% |
| array 3 ints [1,2,3] | 4 | 7 | 7 | 57% | 57% |
| array 10 ints [1..10] | 11 | 22 | 23 | 50% | 48% |
| array 10 floats [1.1..10.1] | 91 | 42 | 43 | 217% | 212% |
| map 2 fields {a:1,b:2} | 7 | 13 | 9 | 54% | 78% |
| user record (5 fields) | 49 | 63 | 46 | 78% | 107% |
| full user record (8 fields) | 102 | 130 | 104 | 78% | 98% |
| nested 3 levels {a:{b:{c:42}}} | 10 | 20 | 12 | 50% | 83% |
| array of 3 user objects | 62 | 98 | 75 | 63% | 83% |
| config object (mixed types) | 87 | 116 | 88 | 75% | 99% |
| array 100 integers [1..100] | 103 | 293 | 295 | 35% | 35% |
