Benchmark
This page summarizes the benchmark results from the Twilic benchmark harness. Measurements are taken using @twilic/core on Node.js 24 (N-API backend) against MessagePack and JSON baselines.
For interactive size comparisons in the browser, see the Playground. For quick terminal benchmarks, use twilic bench.
Setup
The benchmark harness lives in the twilic/benchmark repository. To run it yourself:
git clone https://github.com/twilic/benchmark
cd benchmark
pnpm install
pnpm benchOptions:
pnpm bench -- --backend napi # Node.js N-API (default)
pnpm bench -- --backend wasm # WebAssembly
pnpm bench -- --mode max # maximum benchmark suite
pnpm bench -- --twilic-vs-msgpack-only # hide JSON rows
pnpm bench -- --time-ms 3000 --warmup-ms 1000 # longer windowsWhat Is Measured
| Benchmark | Description |
|---|---|
| Single record encode | Encode one object with a representative schema |
| Single record decode | Decode one Twilic payload |
| 256-record batch encode | Encode 256 same-shape records |
| 256-record batch decode | Decode a 256-record Twilic batch |
| MessagePack encode/decode | Baseline for single and batch |
| JSON stringify/parse | Baseline for single and batch |
| State patch encode | encodePatch on a hot object stream |
| Transport-JSON fast path | encodeTransportJson / decodeToTransportJson |
Payload Size Comparison
Twilic's size advantage grows with repetition. Representative results on a 256-record batch with a 6-field object schema:
| Format | Single record (bytes) | 256-record batch (bytes) | Ratio vs JSON |
|---|---|---|---|
| JSON | ~120 | ~30,720 | 1.0× |
| MessagePack | ~80 | ~20,480 | 0.67× |
| Twilic (Dynamic) | ~75 | ~8,960 | 0.29× |
| Twilic (Columnar) | ~70 | ~4,200 | 0.14× |
Numbers are approximate; exact values depend on schema and data distribution.
The key insight: Twilic's advantage is multiplicative at batch scale. Key interning and shape interning eliminate repeated field-name overhead across every record in the batch.
Throughput
On a single record, Twilic and MessagePack have comparable throughput — both are significantly faster than JSON parse/stringify. Twilic's overhead vs MessagePack on a single record is encoder state initialization, which is amortized across a batch.
For the N-API backend on Node.js 24, typical throughput:
| Operation | Twilic (N-API) | MessagePack |
|---|---|---|
| Single encode | ~500k ops/s | ~550k ops/s |
| Single decode | ~480k ops/s | ~530k ops/s |
| 256-record batch encode | ~8k batches/s | ~3.5k batches/s |
| 256-record batch decode | ~7.5k batches/s | ~3k batches/s |
Throughput numbers are illustrative; run the harness for your exact hardware.
Max Speed Tips
- Use
--backend napion Node.js (highest throughput) - Use Node.js 24+ (project baseline, JIT-optimized)
- Increase run windows for stability:
--time-ms 3000 --warmup-ms 1000 - For hot paths: pre-serialize once with transport-JSON APIs, then use raw encode methods
- Prefer columnar batch (
col_batch) for large, regular datasets
State Patch Performance
On a hot object stream where 2 of 20 fields change per tick, encodePatch reduces payload size by 85–92% compared to re-encoding the full object. The patch overhead (patch header + changed field encoding) is small relative to the savings.
Running the Full Suite
# Full suite
pnpm bench -- --mode full
# Extended suite with all workloads
pnpm bench -- --mode max
# Twilic vs MessagePack only (no JSON rows)
pnpm bench -- --twilic-vs-msgpack-only
# WASM backend comparison
pnpm bench -- --backend wasm --time-ms 2000Results are printed as formatted CLI tables with throughput (ops/sec) and payload size columns side by side.