Systems-Grade Benchmarking
SoulState is engineered for high-density reactive environments. Unlike libraries optimized for simple benchmarks with 10 subscribers, SoulState is designed to maintain predictable performance as your application scales to 100,000+ active subscribers.
📊 Sparse Update Supremacy
Workload: 100,000 subscribers, 100 state keys, 1% update impact (surgical).
In this scenario, updating a single key only affects 1,000 out of 100,000 subscribers.
| Library | Throughput (hz) | Scalability Identity |
|---|---|---|
| SoulState | ~250,900 | Surgical DAG Runtime |
| Jotai | ~193,800 | Atomic State |
| Zustand | ~280 | Global Broadcast |
| Redux Toolkit | ~170 | Centralized Reducer |
Analysis: The O(M) Advantage
- Zustand/RTK: These libraries use a global broadcast model ($O(N)$). When any state changes, they must iterate through all 100,000 subscribers and run selectors.
- SoulState: Uses an Invalidation Graph ($O(M)$). It knows exactly which 1,000 subscribers care about the changed key and notifies them directly, skipping the other 99,000 entirely.
🏗️ Deep Propagation Performance
Workload: 10 levels of nested computed state, 1,000 subscribers.
SoulState's level-based propagation ensures that derived state is recomputed only once per update, in the correct topological order.
| Library | Throughput (hz) | Consistency |
|---|---|---|
| SoulState | ~549,900 | Deterministic / Glitch-Free |
| Zustand | ~19,700 | Manual Optimization Required |
⚖️ The Systems-Grade Tradeoff
SoulState is not a "silver bullet." Its architecture makes specific tradeoffs to achieve its scalability.
1. Initialization Overhead
Building the Invalidation Graph takes time. SoulState is significantly slower than Zustand at creating subscribers.
- Zustand: Optimized for high-churn, short-lived components.
- SoulState: Optimized for long-lived, high-density reactive graphs.
2. Memory Footprint
SoulState maintains a bidirectional graph and topological levels for every subscriber.
- Overhead: ~150-200 bytes per subscriber node.
- Total: 100,000 subscribers will consume ~20MB of heap for the dependency graph.
🔍 Benchmark Methodology
All benchmarks are executed using vitest bench with the following environment:
- Environment: Node.js 20+ / V8 Engine.
- Workload: Identical selector and listener logic across all competitors.
- Warmup: 500ms warmup period to allow JIT optimization.
- Repetition: Minimum 10 runs to ensure statistical stability.
Reproducibility
You can reproduce these results by running:
npm run test:bench
🛠️ Performance Best Practices
- Granular Selectors: Always select the smallest possible piece of state to minimize $M$ (affected nodes).
- Computed Chains: Use
computednodes for expensive transformations. SoulState's graph will ensure they are only re-run when their specific dependencies change. - Avoid Selective "God Objects": If your selector returns a massive object that changes frequently, you lose the benefits of sparse invalidation.
Performance Summary
SoulState is the right choice when your application's update complexity outweighs its initialization complexity. If you have 10,000+ components that need to stay in sync with a central store, SoulState's graph architecture provides the only path to predictable 60fps performance.