Skip to main content

Advanced

3 min read

Benchmarks

Directive's constraint engine is designed for real-time applications. These benchmarks measure every hot path.


Results

All numbers measured on an Apple M4 Max, Node.js 22, using Vitest's built-in bench API. Run pnpm bench to reproduce.

Fact Mutations

Operationops/secLatency
Single fact read18,873,45253ns
Single fact set6,332,174158ns
100 facts batched127,4867.8μs
100 fact reads via proxy142,3577.0μs

Derivations

Operationops/secLatency
Simple derivation (invalidate + read)1,880,103532ns
10 chained derivations259,6803.9μs
50 chained derivations55,56818μs
Invalidate 20 derivations (1 fact change)1,490,468671ns

Constraint Evaluation + Reconciliation

Operationops/secLatency
No-op reconcile (nothing changed)67,37915μs
Single constraint + resolver56,56918μs
10 constraints, 1 triggers28,38235μs
Minimal cycle (1 fact → 1 constraint → 1 resolver)45,72122μs
Medium system (5 facts → 3 constraints → 3 resolvers → 5 derivations)18,78053μs

Real-World Scenarios

Scenarioops/secLatencyDescription
Traffic light27,00937μs9 event dispatches → 3 constraint transitions
Auth flow35,33428μslogin → token → profile (cascading constraints)

Head-to-Head Comparison

All libraries benchmarked side-by-side on the same machine (M4 Max, Node 22) using identical operations via Vitest bench. Run pnpm bench -- --grep Comparison to reproduce.

Single Read (ops/sec)

Libraryops/secRelative
Preact Signals33,268,4041.00x
Zustand33,211,3231.00x
XState32,825,1060.99x
Redux Toolkit32,732,6590.98x
MobX23,280,1130.70x
Directive18,281,7920.55x
Jotai9,092,9140.27x

Single Write (ops/sec)

Libraryops/secRelative
Preact Signals30,237,5721.00x
Zustand16,601,2580.55x
MobX9,220,8500.31x
Directive7,600,2370.25x
Redux Toolkit2,347,4090.08x
Jotai2,143,9790.07x
XState1,247,2730.04x

Derived/Computed Value (write + read, ops/sec)

Libraryops/secRelative
Preact Signals22,684,1221.00x
Zustand13,012,6220.57x
MobX4,936,0020.22x
Redux Toolkit2,307,7940.10x
Directive2,061,3000.09x
XState1,252,3950.06x
Jotai830,9720.04x

1,000 Write+Read Cycles (ops/sec)

Libraryops/secRelative
Preact Signals83,1121.00x
Zustand26,6090.32x
Directive9,6670.12x
MobX9,3180.11x
Redux Toolkit2,4600.03x
Jotai1,8240.02x
XState1,2220.01x

What Only Directive Can Do

The comparison above measures raw state operations. Directive is slower on pure reads/writes because every access goes through a Proxy that enables auto-tracking. But Directive is the only library that also does:

CapabilityDirectiveOthers
Full reconcile (constraints + resolvers)18,780/s (53μs)
Auth flow (3-step cascade)35,334/s (28μs)
Causal debugging (explain())YesNo
Auto-tracked derivationsYesOnly MobX, Signals
Constraint-driven cache invalidationYesNo
Time-travel debuggingYesOnly Redux (via devtools)
Zero dependenciesYesOnly Zustand, Jotai

The trade-off: Directive's proxy overhead costs ~2x vs plain object reads, but enables auto-tracking, causal debugging, and the constraint engine – features no other library provides.


Why It's Fast

Three optimizations account for most of the performance:

  1. Module-level __DEV__ const – V8's JIT compiler can't optimize proxy traps that contain process.env.NODE_ENV checks (treated as potentially side-effectful). Hoisting to a module-level const lets V8 compile the proxy handler to native code. This alone gave a 3.1x improvement on reads.

  2. queueMicrotask instead of setTimeout(0) – The settle() function used setTimeout(0) to yield before checking settlement. Browsers clamp setTimeout(0) to ~1-4ms. Replacing with queueMicrotask resolves within the same microtask queue, eliminating ~1ms of scheduler latency per cycle. This gave a 23-97x improvement on reconciliation.

  3. Fast-path trackAccess – 99% of fact reads happen outside derivation computation. An early return when trackingStack.length === 0 skips the entire tracking mechanism, saving 3 function calls per read.


Running Benchmarks

pnpm bench

Individual categories:

pnpm bench -- --grep "Fact Mutations"
pnpm bench -- --grep "Derivations"
pnpm bench -- --grep "Reconciliation"

Next Steps

Previous
SSR & Hydration

Stay in the loop. Sign up for our newsletter.

We care about your data. We'll never share your email.

Powered by Directive. This signup uses a Directive module with facts, derivations, constraints, and resolvers – zero useState, zero useEffect. Read how it works

Directive - Constraint-Driven Runtime for TypeScript | AI Guardrails & State Management