alien-signals vs Reflex Quant: Benchmark and Design
Two small, framework-agnostic signals runtimes. One is known for raw speed. The other was derived from a written contract and then measured. They agree on the API and differ in what they consider part of the job.
alien-signals is a fast, widely used signals library. Reflex Quant treats it the way its architecture rules treat every other runtime: as a source of counterexamples and workloads, not of obligations. It is benchmarked against alien-signals 3.2.1 on every CI run, and before any timing both must produce the same answers on every scenario.
At a glance
| Reflex Quant | alien-signals 3.2.1 | |
|---|---|---|
| Reactive primitives | signal, computed, effect | signal, computed, effect, effectScope |
| Reading and writing | functions over handles: get, peek, set, update | the signal is a function: call it to read, call it with a value to write |
| Previous value in a computed | computed((prev) => …, initial): the last committed value | see its documentation |
| Manual invalidation | none | trigger |
| Reordered reads (256 sources) | 0 relations created or removed per pass | 255 relinked per pass |
| Depth of a chain | bounded by memory: one explicit work stack, no recursion | see its documentation |
| Specified by | a written contract, an executable spec, differential tests | its test suite |
| Size (ESM, gzip) | about 2.2 KB | see bundlephobia |
The structural difference: a reorder
When a computation reads the same sources in a different order, something has to happen to its dependency list. alien-signals unlinks and relinks on every out-of-place read. Quant keeps the relation and moves it.
| edges created | edges removed | |
|---|---|---|
| Reflex Quant | 0 | 0 |
| alien-signals 3.2.1 | 255 | 255 |
node bench/structure.mjs.This is counted, not timed, so it does not depend on a machine. It is also where the timing gap is widest: on the three reorder scenarios Quant takes 0.15 to 0.17 of alien-signals' time, and on a shared graph whose read order changes every pass, 0.22. How the old relation is found without a hash table: dynamic dependency tracking.
Writes inside an effect: two findings
The Fireflies model was ported to six runtimes on a fixed 64 × 40 grid and checked against a hand-written worklist after every tick. It is a hard model for a reactive runtime: a firefly that flashes writes into its neighbours' inboxes from inside its own transition, and some of those writes land on a computation that is still running. The code, the ports and the commands are in bench/fireflies.
A wake-up is lost. Quant, Preact Signals, Vue, Solid and Angular's signal primitives end every one of 1,500 ticks in the same state as the worklist. The direct alien-signals port differs on the first tick: fireflies are left with unread pulses. The case reduces to two effects. A writes into B's inbox; B's effect runs inside that write and writes back into A's inbox while A is still running.
- alien-signals 3.2.1
- A runs
- A writes B's inbox
- B runs inside A's write depth 2
- B writes A's inbox
- A is still running: not run again
- A's write returns
- A ends
- 0.2 left unread in A's inbox
- Reflex Quant 1.1.2
- A runs
- A writes B's inbox: B is queued
- A's write returns
- A ends
- B runs depth 1
- B writes A's inbox: A is queued
- A runs again, reads 0.2
- inbox empty
In alien-signals the effect is not run again for a dependency that was written during its own run. Preact Signals delivers the pulse too. Quant never reaches that position: an effect does not run inside another effect's write. Effects run one at a time from the host's queue, so B runs after A has returned, and B's write wakes A like any other write. If a write does land on an effect while it runs, the contract covers that case as well (W2: a watcher invalidated during its own run is delivered again). Whether alien-signals intends its behaviour is a question for its maintainers; the test only shows what it does. To get the right answer the port needs a repair written by hand: after every tick, re-trigger each firefly that still has mail, until none does.
An avalanche lives on the call stack. In alien-signals a write inside an effect runs the dependent effect inside that write, so a cascade nests effects in one another. On this model the nesting reaches 2,560, the whole field. On Node's default stack the repaired port overflowed at tick 262 with 2,457 effects nested in one run and completed in another: at this size it sits on the limit. In Quant the trace above stays at depth 1 however long the cascade: effects run from a queue, and propagation runs on the runtime's own work stack, bounded by memory.
The same ports on a 200 × 200 field, 40,000 fireflies, 900 ticks, default stack size:
| result | |
|---|---|
| Reflex Quant | same state as the worklist; all 40,000 flash in one tick; 5.3 s |
| Angular signal primitives | same state as the worklist; 7.6 s |
| Solid | same state as the worklist; 44.7 s |
| Preact Signals | Cycle detected at tick 167, its limit on repeated effect runs |
| Vue reactivity | call stack overflow at tick 341 |
| alien-signals, repaired port | call stack overflow at tick 247 |
One model, one machine (Node 25.2.0), each port one reasonable way to write it. This is a probe of semantics and stack behaviour, not a ranking; the timings are in the folder's README.
Where alien-signals is faster
On the shortest paths. Reading a clean value (static.read-clean) costs Quant 1.22 of alien-signals' time, and mounting effects (lifecycle.mount-100) 1.04. A read that finds nothing to do is almost all call overhead, and alien-signals has less of it. The pattern across the suite is consistent: the more a scenario looks like a graph, with shared nodes, fan-in and changing read order, the further Quant pulls ahead; the more it looks like a single function call, the closer alien-signals gets, and on the two above it wins.
Benchmarks
- On the project's CI suite (18 scenarios, run 42794143933, 1.1.2): geometric mean 1.03× the time of the better of Reflex and alien-signals, 0.99× Reflex, 0.45× alien-signals. Faster than both on 7 of 18 scenarios, within 25 % of the better one on 17.
- Reorders allocate nothing: with 256 sources rotated every pass, Quant creates and removes no dependency relations, where alien-signals relinks 255.
- Reflex remains faster on reorders and sorts (Quant takes 1.20–1.43× its time there).
The suite is this project's own; lower is better. Node 22.23.4, 9 rounds; each ratio measured within one runner; Reflex bf71877, alien-signals 3.2.1. Earlier snapshots: REPORT.md (Q6), HISTORY.md.
Per-scenario chart and method: benchmarks.
What Quant leaves out on purpose
effectScope, nested-effect ownership and manual invalidation are real answers to real problems: who owns a group of effects, and how to tell the graph that a mutable container changed. They are answers to different questions from the one Quant asks. Its rule for admitting a mechanism is a named obligation and a minimal program that violates it without the mechanism. "Another runtime has it" is explicitly not a reason. So Quant has dispose for one node and no notion of a scope; ownership is left to the framework above it.
That is a cost if you want those features in the box, and the reason the runtime is small if you do not.
What Quant writes down
What a computed depends on after it throws. Whether A → B → A is a change. What happens to a computation whose source is written while it runs. Whether an obligation to run survives a failure. Quant answers each of these in its contract, executes the answers against a specification on over 140,000 programs, and removes each mechanism in turn to check that a test notices. This page makes no claim about how alien-signals behaves in those cases; only that Quant's behaviour is specified and tested there.
When to choose which
Choose alien-signals if you want effect scopes in the library, a large user base, and the fastest possible read of a clean value. Choose Reflex Quant if your graphs reorder and share, if you want behaviour under failure written down, or if you want a runtime small enough to read in an afternoon and argue with.
Try Quant
npm install reflex-quantEvidence
- bench/: scenarios, adapters and structure counters
- REPORT.md: research report and benchmark tables
- EDGE-CHURN.md: dependency edge churn study
- CONTRACT.md: invariants and structural bounds
FAQ
Is Reflex Quant an alternative to alien-signals?
Yes: both provide framework-agnostic signal, computed and effect. Quant is smaller in surface, reuses dependency relations on reorder, and is specified by a written contract.
Is Reflex Quant faster than alien-signals?
On the project's own 18-scenario CI suite its geometric-mean time is 0.45 of alien-signals' (CI run 42794143933). The suite is the project's own; per-scenario numbers are on the benchmarks page of this site.