Skip to content

Bun

This page summarizes Bun benchmark runs for Knitting on bun 1.3.6 (arm64-darwin).

This benchmark compares one round-trip between a main thread and workers using different transports. Knitting keeps the lowest overhead in this setup:

  • 1 message: Knitting is about 5.7x faster than worker postMessage, 9.5x faster than websocket, and 21x faster than HTTP.
  • 25 messages: Knitting is about 7.4x faster than worker postMessage.
  • 50 messages: Knitting is about 7x faster than worker postMessage.
Bun IPC benchmark

These charts compare the same payload families sent through Knitting and Bun workers.

With a single value per call, Knitting is consistently faster:

  • For small primitives, Knitting is roughly ~6-17x faster than workers.
  • For string/array/object payloads, Knitting is usually around ~4-6x faster.
  • For larger payloads, Knitting still holds a clear advantage (for example, big object: 3.97 µs vs 16.38 µs, about 4.1x faster).
Bun knitting vs worker benchmark 1

At 100 messages per iteration, the gap remains strong:

  • Typical primitives stay around ~7-9x faster with Knitting.
  • Heavier payloads still keep a clear edge at roughly ~3.7-3.9x faster.
  • Batching improves throughput for both, but Knitting remains lower-overhead across payload classes.
Bun knitting vs worker benchmark 100

This benchmark increases payload size from 32 B up to 1,048,576 B (1 MiB) and reports batched cost with batch=64.

Using the 1048576 B row (avg) from the batch=64 run, one-way transfer throughput is:

  • string: 5.66 ms/iter -> 11.86 GB/s
  • Uint8Array: 4.14 ms/iter -> 16.21 GB/s

Interpretation:

  • Bun remains the fastest runtime in this batched 1 MiB shape for both string and binary payloads.
  • The Uint8Array path clears 16 GB/s one-way equivalent in this run, with string close to 12 GB/s.
bun_call-growth-batch.md
clk: ~3.68 GHz
cpu: Apple M3 Ultra
runtime: bun 1.3.6 (arm64-darwin)
| • call growth batch string (ascii 32..1048576 x4, batch=64) | avg | min | p75 | p99 | max |
| --------- | ---------------- | ----------- | ----------- | ----------- | ----------- |
| 32 B | ` 25.85 µs/iter` | ` 11.46 µs` | ` 29.63 µs` | ` 80.08 µs` | ` 1.94 ms` |
| 128 B | ` 22.32 µs/iter` | ` 20.54 µs` | ` 22.99 µs` | ` 23.68 µs` | ` 25.10 µs` |
| 512 B | ` 28.31 µs/iter` | ` 25.67 µs` | ` 29.32 µs` | ` 29.67 µs` | ` 30.50 µs` |
| 2048 B | ` 67.00 µs/iter` | ` 28.96 µs` | ` 70.29 µs` | `247.21 µs` | ` 2.73 ms` |
| 8192 B | `130.66 µs/iter` | ` 71.17 µs` | `142.79 µs` | `323.83 µs` | ` 1.84 ms` |
| 32768 B | `208.32 µs/iter` | `123.29 µs` | `214.96 µs` | `652.54 µs` | ` 1.84 ms` |
| 131072 B | `592.88 µs/iter` | `418.63 µs` | `592.92 µs` | ` 1.88 ms` | ` 2.25 ms` |
| 524288 B | ` 2.82 ms/iter` | ` 1.77 ms` | ` 3.36 ms` | ` 6.20 ms` | ` 6.64 ms` |
| 1048576 B | ` 5.66 ms/iter` | ` 3.85 ms` | ` 5.85 ms` | ` 10.93 ms` | ` 10.98 ms` |
| • call growth batch uint8array (32..1048576 x4, batch=64) | avg | min | p75 | p99 | max |
| --------- | ---------------- | ----------- | ----------- | ----------- | ----------- |
| 32 B | ` 25.21 µs/iter` | ` 13.38 µs` | ` 30.13 µs` | ` 56.04 µs` | ` 1.53 ms` |
| 128 B | ` 23.71 µs/iter` | ` 20.35 µs` | ` 25.02 µs` | ` 25.26 µs` | ` 26.54 µs` |
| 512 B | ` 22.87 µs/iter` | ` 20.79 µs` | ` 23.68 µs` | ` 23.82 µs` | ` 24.01 µs` |
| 2048 B | ` 67.13 µs/iter` | ` 33.50 µs` | ` 70.92 µs` | `132.92 µs` | ` 7.98 ms` |
| 8192 B | `116.93 µs/iter` | ` 62.04 µs` | `114.25 µs` | `221.04 µs` | ` 3.13 ms` |
| 32768 B | `193.72 µs/iter` | `131.08 µs` | `173.92 µs` | ` 1.01 ms` | ` 2.90 ms` |
| 131072 B | `571.40 µs/iter` | `348.29 µs` | `523.71 µs` | ` 2.01 ms` | ` 2.32 ms` |
| 524288 B | ` 2.37 ms/iter` | ` 1.59 ms` | ` 3.00 ms` | ` 5.19 ms` | ` 6.12 ms` |
| 1048576 B | ` 4.14 ms/iter` | ` 3.08 ms` | ` 4.64 ms` | ` 6.30 ms` | ` 9.65 ms` |

This stress test computes prime numbers over a large range, then serializes and parses large JSON payloads:

const N = 10_000_000; // search range: [1..N]
const CHUNK_SIZE = 250_000;

Even under this heavier workload, parallel workers scale well:

  • main + 1 extra thread: ~1.8x faster than main only.
  • main + 2 extra threads: ~2.5x faster than main only.
  • main + 3 extra threads: ~3.3x faster than main only.
  • main + 4 extra threads: ~3.8x faster than main only.
bun_withload.md
clk: ~3.69 GHz
cpu: Apple M3 Ultra
runtime: bun 1.3.6 (arm64-darwin)
| • knitting: primes up to 10,000,000 (chunk=250,000) | avg | min | p75 | p99 | max |
| ----------------------------------- | ---------------- | ----------- | ----------- | ----------- | ----------- |
| main | `572.57 ms/iter` | `569.05 ms` | `573.73 ms` | `576.83 ms` | `577.70 ms` |
| main + 1 extra threads → full range | `304.05 ms/iter` | `299.51 ms` | `305.94 ms` | `310.39 ms` | `310.63 ms` |
| main + 2 extra threads → full range | `224.68 ms/iter` | `220.21 ms` | `228.08 ms` | `230.10 ms` | `230.84 ms` |
| main + 3 extra threads → full range | `179.33 ms/iter` | `174.37 ms` | `181.15 ms` | `181.78 ms` | `182.35 ms` |
| main + 4 extra threads → full range | `157.48 ms/iter` | `153.46 ms` | `159.02 ms` | `159.85 ms` | `160.47 ms` |

This benchmark covers primitive, structured, collection, typed-array, error/date/symbol, promise-arg, and static-vs-dynamic allocator paths. Results are reported for count 1 and count 100 to show both per-call latency and batched throughput.

Quick takeaways:

  • In count 100, primitive-style payloads are usually in the ~16-25 µs range, while heavier structured/collection payloads are often ~60-270 µs with occasional larger spikes.
  • The static payload path is usually around ~1.3x-3.1x faster than dynamic allocator paths (for example: string ~1.8x, json ~2.1x, Uint8Array ~1.3x, symbol ~3.1x at count 100).

Payload sizes (approximate):

PayloadSize
jsonObj206 B
jsonArr217 B
mapPayload284 B
Uint8Array1024 B
Int32Array1024 B
Float64Array1024 B
BigInt64Array1024 B
BigUint64Array1024 B
DataView1024 B
smallU8480 B
largeU8481 B
bun_types_knitting.md
payload sizes (approx bytes):
jsonObj: 206 bytes
jsonArr: 217 bytes
stringHuge: 1024 bytes
Uint8Array: 1024 bytes
Int32Array: 1024 bytes
Float64Array: 1024 bytes
BigInt64Array: 1024 bytes
BigUint64Array: 1024 bytes
DataView: 1024 bytes
clk: ~3.69 GHz
cpu: Apple M3 Ultra
runtime: bun 1.3.6 (arm64-darwin)
| • knitting-types 1 | avg | min | p75 | p99 | max |
| --------------------- | ---------------- | ----------- | ----------- | ----------- | ----------- |
| number -> (1) | ` 1.88 µs/iter` | `459.00 ns` | ` 2.83 µs` | ` 8.17 µs` | `433.21 µs` |
| bigint small -> (1) | ` 2.19 µs/iter` | ` 1.50 µs` | ` 2.48 µs` | ` 3.01 µs` | ` 3.07 µs` |
| bigint large -> (1) | ` 4.01 µs/iter` | ` 2.04 µs` | ` 4.04 µs` | ` 12.50 µs` | ` 1.73 ms` |
| boolean true -> (1) | ` 1.33 µs/iter` | `707.16 ns` | ` 1.68 µs` | ` 2.48 µs` | ` 2.74 µs` |
| boolean false -> (1) | ` 1.09 µs/iter` | `710.70 ns` | ` 1.35 µs` | ` 2.14 µs` | ` 2.47 µs` |
| undefined -> (1) | ` 1.16 µs/iter` | `648.72 ns` | ` 1.51 µs` | ` 2.57 µs` | ` 2.89 µs` |
| null -> (1) | ` 1.03 µs/iter` | `649.21 ns` | ` 1.30 µs` | ` 2.70 µs` | ` 2.92 µs` |
| string -> (1) | ` 2.39 µs/iter` | `625.00 ns` | ` 2.92 µs` | ` 7.88 µs` | `448.88 µs` |
| json object -> (1) | ` 3.59 µs/iter` | ` 3.00 µs` | ` 3.82 µs` | ` 4.37 µs` | ` 4.37 µs` |
| json array -> (1) | ` 4.61 µs/iter` | ` 4.15 µs` | ` 4.76 µs` | ` 5.04 µs` | ` 5.09 µs` |
| Uint8Array -> (1) | ` 4.34 µs/iter` | ` 1.54 µs` | ` 4.67 µs` | ` 14.04 µs` | ` 3.75 ms` |
| ArrayBuffer -> (1) | ` 3.98 µs/iter` | ` 1.33 µs` | ` 4.42 µs` | ` 11.83 µs` | ` 3.49 ms` |
| Buffer -> (1) | ` 3.15 µs/iter` | ` 2.44 µs` | ` 3.46 µs` | ` 3.79 µs` | ` 3.84 µs` |
| string huge -> (1) | ` 3.51 µs/iter` | ` 1.29 µs` | ` 3.79 µs` | ` 11.96 µs` | ` 1.59 ms` |
| Int32Array -> (1) | ` 3.55 µs/iter` | ` 2.61 µs` | ` 3.92 µs` | ` 4.21 µs` | ` 4.25 µs` |
| Float64Array -> (1) | ` 3.00 µs/iter` | ` 1.08 µs` | ` 3.38 µs` | ` 8.79 µs` | ` 1.68 ms` |
| BigInt64Array -> (1) | ` 3.48 µs/iter` | ` 2.54 µs` | ` 3.86 µs` | ` 4.45 µs` | ` 4.65 µs` |
| BigUint64Array -> (1) | ` 3.57 µs/iter` | ` 2.58 µs` | ` 4.05 µs` | ` 4.84 µs` | ` 4.90 µs` |
| DataView -> (1) | ` 3.24 µs/iter` | ` 2.50 µs` | ` 3.50 µs` | ` 4.65 µs` | ` 5.04 µs` |
| Date -> (1) | ` 1.68 µs/iter` | `541.00 ns` | ` 1.96 µs` | ` 5.21 µs` | `466.54 µs` |
| Symbol.for -> (1) | ` 2.41 µs/iter` | ` 1.76 µs` | ` 2.64 µs` | ` 3.04 µs` | ` 3.04 µs` |
| • knitting-types 100 | avg | min | p75 | p99 | max |
| ----------------------- | ---------------- | ----------- | ----------- | ----------- | ----------- |
| number -> (100) | ` 32.00 µs/iter` | ` 13.96 µs` | ` 27.54 µs` | `215.88 µs` | ` 3.23 ms` |
| bigint small -> (100) | ` 30.26 µs/iter` | ` 27.43 µs` | ` 31.73 µs` | ` 32.18 µs` | ` 35.93 µs` |
| bigint large -> (100) | `122.70 µs/iter` | ` 84.33 µs` | `120.96 µs` | `425.79 µs` | ` 1.91 ms` |
| boolean true -> (100) | ` 27.23 µs/iter` | ` 24.14 µs` | ` 27.49 µs` | ` 29.92 µs` | ` 34.21 µs` |
| boolean false -> (100) | ` 28.04 µs/iter` | ` 23.23 µs` | ` 29.87 µs` | ` 32.86 µs` | ` 36.96 µs` |
| undefined -> (100) | ` 28.24 µs/iter` | ` 22.49 µs` | ` 29.58 µs` | ` 30.68 µs` | ` 32.45 µs` |
| null -> (100) | ` 25.01 µs/iter` | ` 22.17 µs` | ` 26.19 µs` | ` 27.17 µs` | ` 27.45 µs` |
| string -> (100) | ` 28.18 µs/iter` | ` 23.32 µs` | ` 30.81 µs` | ` 33.08 µs` | ` 41.07 µs` |
| json object -> (100) | `122.98 µs/iter` | ` 93.67 µs` | `125.88 µs` | `223.46 µs` | ` 1.62 ms` |
| json array -> (100) | `149.52 µs/iter` | `113.92 µs` | `154.54 µs` | `279.08 µs` | ` 1.66 ms` |
| Uint8Array -> (100) | `112.02 µs/iter` | ` 54.00 µs` | `112.13 µs` | `928.79 µs` | ` 3.12 ms` |
| ArrayBuffer -> (100) | `115.93 µs/iter` | ` 61.33 µs` | `113.54 µs` | `922.46 µs` | ` 3.59 ms` |
| Buffer -> (100) | `104.68 µs/iter` | ` 44.46 µs` | `115.63 µs` | `747.96 µs` | ` 2.11 ms` |
| string huge -> (100) | ` 93.47 µs/iter` | ` 46.04 µs` | `110.38 µs` | `207.17 µs` | ` 1.73 ms` |
| Int32Array -> (100) | `101.19 µs/iter` | ` 49.92 µs` | ` 98.04 µs` | `900.71 µs` | ` 3.78 ms` |
| Float64Array -> (100) | ` 71.52 µs/iter` | ` 37.50 µs` | ` 82.33 µs` | `167.50 µs` | ` 1.58 ms` |
| BigInt64Array -> (100) | `103.28 µs/iter` | ` 50.00 µs` | ` 98.63 µs` | `920.00 µs` | ` 3.84 ms` |
| BigUint64Array -> (100) | `101.80 µs/iter` | ` 50.13 µs` | ` 98.13 µs` | `908.42 µs` | ` 4.21 ms` |
| DataView -> (100) | `102.14 µs/iter` | ` 50.29 µs` | ` 98.92 µs` | `895.21 µs` | ` 3.87 ms` |
| Date -> (100) | ` 31.00 µs/iter` | ` 27.10 µs` | ` 32.35 µs` | ` 34.37 µs` | ` 38.53 µs` |
| Symbol.for -> (100) | ` 37.43 µs/iter` | ` 21.46 µs` | ` 47.08 µs` | ` 83.50 µs` | ` 1.56 ms` |
| • knitting-promise-args 1 | avg | min | p75 | p99 | max |
| --------------------- | ---------------- | ----------- | ----------- | ----------- | ----------- |
| promise number -> (1) | ` 2.44 µs/iter` | ` 1.76 µs` | ` 2.78 µs` | ` 3.16 µs` | ` 3.20 µs` |
| promise object -> (1) | ` 3.13 µs/iter` | ` 2.35 µs` | ` 3.34 µs` | ` 3.74 µs` | ` 3.79 µs` |
| • knitting-promise-args 100 | avg | min | p75 | p99 | max |
| ----------------------- | ---------------- | ----------- | ----------- | ----------- | ----------- |
| promise number -> (100) | ` 43.54 µs/iter` | ` 39.69 µs` | ` 45.25 µs` | ` 47.23 µs` | ` 48.48 µs` |
| promise object -> (100) | ` 61.77 µs/iter` | ` 38.13 µs` | ` 68.83 µs` | `122.88 µs` | ` 1.49 ms` |