Performance

Continuously verified
These benchmarks run on every commit. If a regression is detected, the PR is blocked until performance is restored.

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

BenchmarkSafari (JSC)Chrome (V8)
atom lifecycle (create+100get+100set)23.0x faster4.8x faster
atom(1)24.3x faster1.9x faster
get 1000 atoms39.8x faster13.8x faster
set 1000 atoms9.9x faster4.8x faster
set(atom, curr => curr+1)26.7x faster6.0x faster
set(atom, value)41.8x faster5.4x faster
set(atom) with 10 subs29.1x faster6.1x faster
store.get(atom)9.8x faster5.1x faster

Selectors

BenchmarkSafari (JSC)Chrome (V8)
selector(fn)8.3x faster1.3x faster
set + read 10 selectors4.7x faster2.8x faster
set + read 100 selectorFamily entries4.5x faster1.9x faster
set + read 100 selectors5.8x faster1.9x faster
set + read through 5 chained selectors3.1x faster2.0x faster

Transactions

BenchmarkSafari (JSC)Chrome (V8)
txn: 10 atoms × 10 selectors, set + read4.4x faster1.7x faster
txn: 10 atoms × 10 selectors, with subs7.5x faster3.2x faster
txn: 10 atoms × 100 selectors, set + read5.5x faster1.8x faster
txn: asymmetric DAG shared sink5.3x faster2.4x faster
txn: cross-atom 1000 selectors, set + read6.7x faster2.0x faster
txn: cross-atom 1000 selectors, with subs23.9x faster14.5x faster
txn: large asymmetric DAG (1000 leaves × 50 chain)4.9x faster2.7x faster

Store

BenchmarkSafari (JSC)Chrome (V8)
createStore16.1x faster11.0x faster
sub + unsub7.9x faster3.5x faster
sub+unsub on chain of 100 unsubscribed derived deps1.1x faster1.2x slower
sub+unsub on chain of 50 unsubscribed derived deps1.4x faster1.2x slower
sub+unsub on chain of 500 unsubscribed derived deps1.2x faster1.1x slower

Families

BenchmarkSafari (JSC)Chrome (V8)
atomFamily(id)2.8x faster1.1x faster
atomFamily(id) cache hit1.1x faster5.5x faster
selectorFamily(id)1.3x faster1.2x faster
Where Valdres still trails Jotai

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 depsChrome (V8): 1.2x slower
  • sub+unsub on chain of 50 unsubscribed derived depsChrome (V8): 1.2x slower
  • sub+unsub on chain of 500 unsubscribed derived depsChrome (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.

What these numbers are (and aren't)
Every benchmark here compares the core Valdres engine against Jotai at the JavaScript level. They are not framework-rendering benchmarks, and Valdres does not claim to be faster than a framework's native reactivity (e.g. Svelte runes). The adapters exist to share one store across frameworks, not to outrun them.

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

Performance is tracked over time on every push to main. View the live, always-current numbers and history at bencher.dev/perf/valdres.