HighX
Reference

Limits

Measured cost, practical ceilings, and what the numbers do not cover.

Two sets of numbers, measured two ways. Engine figures come from bun run bench and describe algorithmic cost in process. Deployment figures come from bun run load against a real Cloudflare deployment.

Engine figures exclude storage latency, network round trips, WebSocket delivery, and isolate contention. Deployment figures include all of it and are dominated by round trip. In both cases the durable part is how cost scales between rows, not the absolute milliseconds.

Practical ceilings

DimensionComfortableInvestigate beyond
Woken subscribers per write≤ 100500
Live subscriptions per tenant≤ 5001,000
Rows per subscribed query result≤ 1,0005,000
Unindexed subscribed queries0any

Invalidation precision (engine)

The single largest lever in the system.

Query shapeSubscribersWoken per writeWrites/sec
indexed prefix6483,624
full table scan6464130
indexed prefix25632983
full table scan25625633

27× at 64 subscribers, 31× at 256. The difference is not recomputation count — that is shared per query shape — it is that every woken subscriber must be diffed.

Fan-out (engine)

SubscribersWrites/secp50p95
113,6590.074 ms0.092 ms
109,6290.099 ms0.140 ms
1002,2820.409 ms0.711 ms
5005771.758 ms2.368 ms

Patch size

Rows in resultOne-row patchFull snapshotSaving
10163 B4,412 B27×
100164 B10,138 B62×
1,000165 B69,594 B422×

Patch size is independent of result size, which is why preserving resume across reconnects matters. Recomputation still scales with result size, so prefer take().

Reconnect storm (engine)

What a Durable Object pays when it wakes and rebuilds subscriptions, before serving its first event.

Subscriptions restoredTotal (p50)
501.5 ms
2005.5 ms
50016.1 ms

Under load (deployment)

Casep50
sequential mutation97 ms
per-write, 4 concurrent writers27 ms
per-write, 16 concurrent writers9.6 ms
fan-out to 1 subscriber95 ms
fan-out to 20 subscribers101 ms
reconnect, 20 clients at once21 ms

Two relationships matter more than the figures.

Fan-out is flat from 1 to 20 subscribers. 95 ms to 101 ms is inside run-to-run noise: delivering to twenty browsers costs about what delivering to one costs, because the round trip is the bottleneck.

Concurrency is absorbed. Sixteen simultaneous writers cost 9.6 ms each rather than 100 ms each — a Durable Object pipelines even though it serializes its own events.

Tenants scale independently (deployment)

Tenants writing at oncePer-write p50
1141 ms
455 ms
1614.9 ms

Each tenant is its own Durable Object, so this is close to linear and nothing shared shows contention at this size. This is the number to re-check first if the architecture ever grows a shared component.

Waking a quiet tenant (deployment)

p50
warm tenant, first read167 ms
after 15 s idle, first read190 ms

An upper bound rather than a measurement: whether the platform actually evicted the object is its decision, not something a client can force.

Sustained traffic (deployment)

133 write-and-read cycles over 45 seconds, ending with 133 rows: +13.9% latency drift from the first third of the run to the last.

That drift is attributable — rows accumulated throughout and the read was unbounded, so it genuinely got bigger. A leak would show drift with no such explanation, which is why drift is reported rather than an average.

Not measured

Throughput against real Durable Object SQLite in isolation, concurrent writers contending inside one isolate, WebSocket back-pressure, long-term storage growth, and anything soaked for hours.

→ Load testing to measure your own deployment.

On this page