Watch the difference.
Not a simulation.
Search and chart the same event stream with zerocopy shared snapshots, Immutable.js Lists, Immer arrays, and native arrays. Change one filter. Watch all four paths work.
Setup normally runs automatically. This host may need one page refresh to enable shared memory. If your browser blocks service workers or isolation, open this page in a full browser or use a host with COOP/COEP headers. Documentation stays available; there is no copy-mode fallback.
Generated events only. Two real reader workers per path. No artificial delays, hidden work, or assumed winner.
Immutable.js Lists.
Two readers keep real persistent Lists. Batched deltas update live roots; earlier roots stay readable.
- Matching events
- —
- Query + results
- —
- Publish + attach
- —
- Event copies sent
- —
No dataset has been sent.
Real timeline counts appear here.
| Event | Service | Message |
|---|---|---|
| Load all four paths to compare their answers. | ||
Inspect selected event
Select an event row.
Immer arrays.
Two readers keep frozen arrays. Batched produce appends create new roots; earlier roots stay readable.
- Matching events
- —
- Query + results
- —
- Publish + attach
- —
- Event copies sent
- —
No dataset has been sent.
Real timeline counts appear here.
| Event | Service | Message |
|---|---|---|
| Load all four paths to compare their answers. | ||
Inspect selected event
Select an event row.
A dataset per reader.
Both readers use native arrays. By default, updates clone only new events.
- Matching events
- —
- Query + results
- —
- Publish + attach
- —
- Event copies sent
- —
No dataset has been sent.
Real timeline counts appear here.
| Event | Service | Message |
|---|---|---|
| Load all four paths to compare their answers. | ||
Inspect selected event
Select an event row.
Same answer.
Different data movement.
The copy counter counts logical event deliveries to reader workers, not bytes or measured heap. Loading 100,000 events into two readers sends 200,000 event copies per replica path. Shared mode sends memory handles and root descriptors, not cloned event records.
Queries return small result pages in all paths. Those replies, local decoded strings, wrappers, caches, and allocations still have a cost. Zero event copies does not mean zero allocation or zero messages.
Each library gets a fair implementation.
All four paths use the same five primitive columns and search functions. Immutable.js uses real Lists and batched withMutations appends. Queries read Lists directly, with no toJS() conversion. Immer uses native arrays and batched produce appends with default auto-freezing. The default sends only incremental deltas to all three replica paths; full replication is an optional baseline.
Immutable.js shares structure between versions within each worker. It does not share that JavaScript heap across workers. Publication includes plain-column encoding, structured clone, and List reconstruction in each reader. Immer structured-clones its arrays, then freezes the full replica or appends the delta with produce in each reader. Freezing and reader-side updates are included in publication. Changed arrays copy on write within each worker; Immer does not share their backing storage across workers. Freeze retains actual Immer, Immutable.js, and zerocopy roots. Native arrays retain a prefix length for this append-only workload.
Live timings are observations, not a speed claim.
The paths run concurrently and can compete for CPU. Timings separate publication/attachment and queries. Dataset construction and owner-side append work are not in those numbers. Startup and rendering are excluded. Results are checked after timing.
Construction times appear after loading.
Run the controlled four-architecture benchmark →Session limit: 200,000 events. Stop terminates the coordinator and its reader workers. No forced garbage collection. Logs demonstrate a general pattern for editors, tables, catalogs, graphs, and simulations. Explore use cases → · Open the full explorer →
Immer was not measured in the recorded Node.js memory results below. Those historical figures are separate from this live four-path comparison.
Count the memory, too.
100,000 events. One owner and two readers for Shared, Immutable.js and Native replicas. One native owner has no reader replicas. Compare retained data with total process RAM. Each graph has its own labelled, zero-based scale. The full table below shows post-query retained data memory, in MiB. Lower is better.
Retained data memory
Shared WASM capacity is counted once. Includes caches and spare capacity; excludes the empty-worker baseline. Replicated paths: one owner + two readers. One native owner: no reader replicas.
Exact values and trial range
Median and observed min–max of three fresh processes. These ranges are not confidence intervals.
| Design · readers | Median (MiB) | Trial range (MiB) |
|---|---|---|
| zerocopy · 2 readers | 9.10 | 9.09–9.10 |
| Immutable.js · 2 readers | 44.46 | 44.27–44.55 |
| Native replicas · 2 readers | 33.36 | 33.36–33.36 |
| One native owner · 0 readers | 14.04 | 14.04–14.05 |
10 October 2026 · Node v22.23.3 · linux x64 · 3 trials per case. Not browser RAM.
Open SVG · Download chart data
Total process RAM (RSS)
Absolute resident set size (RSS), including workers and runtime overhead. One native owner uses the least RSS in this run. Replicated paths: one owner + two readers. One native owner: no reader replicas.
Exact values and trial range
Median and observed min–max of three fresh processes. These ranges are not confidence intervals.
| Design · readers | Median (MiB) | Trial range (MiB) |
|---|---|---|
| zerocopy · 2 readers | 122.06 | 119.30–122.42 |
| Immutable.js · 2 readers | 212.99 | 206.97–216.69 |
| Native replicas · 2 readers | 164.17 | 163.95–164.23 |
| One native owner · 0 readers | 116.21 | 114.78–117.30 |
10 October 2026 · Node v22.23.3 · linux x64 · 3 trials per case. Not browser RAM.
Open SVG · Download chart data
| Input | Shared | Immutable.js | Native replicas | One native owner |
|---|---|---|---|---|
| Repeated messages | 4.70 | 33.77 | 23.35 | 6.06 |
| Unique messages | 9.10 | 44.46 | 33.36 | 14.04 |
| 20% Unicode prefix | 9.79 | 46.65 | 35.86 | 14.88 |
Includes every worker's JavaScript heap change, tracked buffers, caches, and current shared WASM capacity counted once. Excludes the empty-worker baseline. These are Node.js measurements, not measurements of this device or browser. The live event selector does not change this table.
Total process RAM gives a different result: the one-native-owner control uses the least RSS in this run. Read the full report for RSS, peak process RAM, reader scaling, old snapshots and limits.
Read the memory comparison and method →