Performance
These benchmark the framework-agnostic core engine (atoms, selectors, families, transactions) head-to-head against Jotai v2.19.0 on the same CI runner, across two JavaScript engines: Bun (JavaScriptCore / Safari) and Node.js (V8 / Chrome). The figures below are the latest main run — refreshed automatically, nothing is excluded.
They measure the shared engine, not framework rendering. The React, Vue, Svelte, Solid, and Angular adapters build on each framework's own reactivity — Valdres rides on top of it rather than trying to outrun it, so adapter performance is bounded by the framework itself.
Atoms
| Benchmark | Safari (JSC) | Chrome (V8) |
|---|---|---|
| atom lifecycle (create+100get+100set) | 23.0x faster | 4.8x faster |
| atom(1) | 24.3x faster | 1.9x faster |
| get 1000 atoms | 39.8x faster | 13.8x faster |
| set 1000 atoms | 9.9x faster | 4.8x faster |
| set(atom, curr => curr+1) | 26.7x faster | 6.0x faster |
| set(atom, value) | 41.8x faster | 5.4x faster |
| set(atom) with 10 subs | 29.1x faster | 6.1x faster |
| store.get(atom) | 9.8x faster | 5.1x faster |
Selectors
| Benchmark | Safari (JSC) | Chrome (V8) |
|---|---|---|
| selector(fn) | 8.3x faster | 1.3x faster |
| set + read 10 selectors | 4.7x faster | 2.8x faster |
| set + read 100 selectorFamily entries | 4.5x faster | 1.9x faster |
| set + read 100 selectors | 5.8x faster | 1.9x faster |
| set + read through 5 chained selectors | 3.1x faster | 2.0x faster |
Transactions
| Benchmark | Safari (JSC) | Chrome (V8) |
|---|---|---|
| txn: 10 atoms × 10 selectors, set + read | 4.4x faster | 1.7x faster |
| txn: 10 atoms × 10 selectors, with subs | 7.5x faster | 3.2x faster |
| txn: 10 atoms × 100 selectors, set + read | 5.5x faster | 1.8x faster |
| txn: asymmetric DAG shared sink | 5.3x faster | 2.4x faster |
| txn: cross-atom 1000 selectors, set + read | 6.7x faster | 2.0x faster |
| txn: cross-atom 1000 selectors, with subs | 23.9x faster | 14.5x faster |
| txn: large asymmetric DAG (1000 leaves × 50 chain) | 4.9x faster | 2.7x faster |
Store
| Benchmark | Safari (JSC) | Chrome (V8) |
|---|---|---|
| createStore | 16.1x faster | 11.0x faster |
| sub + unsub | 7.9x faster | 3.5x faster |
| sub+unsub on chain of 100 unsubscribed derived deps | 1.1x faster | 1.2x slower |
| sub+unsub on chain of 50 unsubscribed derived deps | 1.4x faster | 1.2x slower |
| sub+unsub on chain of 500 unsubscribed derived deps | 1.2x faster | 1.1x slower |
Families
| Benchmark | Safari (JSC) | Chrome (V8) |
|---|---|---|
| atomFamily(id) | 2.8x faster | 1.1x faster |
| atomFamily(id) cache hit | 1.1x faster | 5.5x faster |
| selectorFamily(id) | 1.3x faster | 1.2x faster |
Honest accounting — these are the operations where Valdres is currently slower. They're tracked as optimization targets:
sub+unsub on chain of 100 unsubscribed derived deps— Chrome (V8): 1.2x slowersub+unsub on chain of 50 unsubscribed derived deps— Chrome (V8): 1.2x slowersub+unsub on chain of 500 unsubscribed derived deps— Chrome (V8): 1.1x slower
Why the core is fast
The engine is optimized for minimal allocations and cache-friendly data structures — WeakMap-based storage with no intermediate objects, and transactions that batch updates so subscribers fire once.
In React specifically, the adapter is built on useSyncExternalStore (where Jotai uses useEffect + useReducer), which avoids extra renders and effect-cleanup overhead. The other adapters integrate with each framework's native reactivity — Vue refs, Svelte runes, Solid signals, Angular signals — so there the relevant performance is the framework's own.
Running benchmarks locally
# Bun (JSC/Safari engine)
bun run --cwd packages/valdres test:bench
# Node.js (V8/Chrome engine)
bun run --cwd packages/valdres test:bench:node
Historical trends
Performance is tracked over time on every push to main. View the live, always-current numbers and history at bencher.dev/perf/valdres.