# alien-signals: a push-pull signal library that Vue 3.6 adopted

> alien-signals is a TypeScript signal library built around a push-pull propagation algorithm with a deliberately small core. It is worth reading before you adopt it, because the same algorithm now runs inside Vue and XState.

**stackblitz/alien-signals** — 👾 The lightest signal library

- Repository: https://github.com/stackblitz/alien-signals
- Website: https://npmjs.com/package/alien-signals
- Stars: 3,260 · Forks: 126
- Language: TypeScript
- License: MIT
- Published: 2026-09-24 · Updated: 2026-09-24 · Language: en
- Canonical page: https://hysenlabs.com/projects/stackblitz-alien-signals

## What alien-signals is for, and who it is not for

alien-signals is a standalone reactivity primitive, not a UI framework. The package description calls it "The lightest signal library", and the README frames the project as an exploration of a push-pull based signal algorithm rather than a product with a roadmap. You get signals, computed values, effects, effect scopes and a manual trigger, and that is roughly the surface.

The audience is narrower than the npm download graph suggests. The README lists adoption inside vuejs/core, statelyai/xstate, vuejs/language-tools and unuse, and says the core algorithm was ported into Vue 3.6 and into XState's atom architecture. That tells you the intended reader is someone building a reactive layer, a compiler, or a state machine library, not someone who wants to render a todo list. If you are choosing a state manager for an application, the README's own Derived Projects list is the honest answer: React bindings live in Rajaniraiyn/react-alien-signals, and a plain-object interface lives in CCherry07/alien-deepsignals. Neither ships in this package.

## The push-pull algorithm and the constraints on the core

The README describes the implementation as related to four things: Vue 3's propagation algorithm, Preact's double-linked-list approach, Svelte's inner effect scheduling, and the graph-coloring approach used by Reactively. That is the design lineage, and it explains the shape of the code.

The constraint that matters is stated plainly: the algorithmic core in src/system.ts does not use Array, Set or Map, and does not use function recursion. Those restrictions are imposed to keep the core small and predictable, and the README argues that under those conditions "maintaining algorithmic simplicity offers more significant improvements than complex scheduling strategies." That is a real trade-off, not a marketing line. A graph-coloring or scheduler-heavy design buys you finer control over when work runs; this one buys you a core you can read in one sitting. The repository layout backs that up: src/ holds the implementation, and the package exposes both the high-level entry point and a separate ./system entry point, so the algorithmic core is importable on its own.

The author's background is part of the mechanism's story. The README says the same person wrote the reactivity code for both Vue and alien-signals, spent time optimizing Vue 3.4's reactivity system, and started this project after Vue 3.5 moved to a pull-based algorithm similar to Preact. alien-signals is the push-pull branch of that research, and it was later ported back into Vue 3.6 via a pull request.

## Installing alien-signals and running your first effect

The homepage points at npm, and package.json declares pnpm@9.12.0 as the package manager for the repository itself. Installing the library into your own project uses the package name directly.

```bash
npm install alien-signals
```

The README's basic example imports signal, computed and effect from the package root. A signal is a function you call with no argument to read and with one argument to write, and an effect runs immediately on creation and again whenever a dependency changes.

```ts
import { signal, computed, effect } from 'alien-signals';

const count = signal(1);
const doubleCount = computed(() => count() * 2);

effect(() => {
  console.log(`Count is: ${count()}`);
}); // Console: Count is: 1

console.log(doubleCount()); // 2

count(2); // Console: Count is: 2

console.log(doubleCount()); // 4
```

What you should see is the effect logging once on creation, then logging again after count(2) is called, while doubleCount() returns 2 before the write and 4 after. If you are working inside the repository rather than consuming the package, package.json defines build as node ./build.js and test as npm run build && vitest run, so pnpm test builds first and then runs the suite. The bench script runs node --jitless --expose-gc benchs/propagate.mjs, which is how the project measures propagation without JIT warmup effects.

## Effect scopes, nested effects and the manual trigger escape hatch

Three behaviours separate alien-signals from a minimal signal implementation, and each has a documented example.

effectScope returns a stop function. Effects created inside the scope keep running until you call that function, after which writes to the signal produce no console output. This is the cleanup story for a component or a long-lived subsystem.

Nested effects have defined semantics rather than emergent ones. The README states that when an outer effect re-runs, inner effects from the previous run are automatically cleaned up and new inner effects are created if needed, and that outer effects always run before their inner effects. The example shows an inner effect that logs count, and after show(false) a subsequent count(3) produces no output because the inner effect no longer exists. Execution order guarantees like this are what you would otherwise build by hand.

trigger() exists because signals can hold mutable values. If you call arr().push(1) on a signal holding an array, the computed length does not update, because the signal setter was never invoked. The README's example shows length() returning 0 after the push and 1 only after trigger(arr) is called. The README also notes you can trigger multiple signals at once, though the excerpt cuts off mid-example.

## Where the documentation stops and what that costs you

The README is a set of examples, not a reference. It documents signal, computed, effect, effectScope and trigger, and then it stops. There is no documented rollback or transaction primitive, no documented async or suspense story, and no documented batching API. The @lazy-promise/alien-signals derived project exists precisely because async signals are not part of the core, which is a useful signal in itself about where the boundary sits.

The second limitation is the distribution surface. package.json declares exports for ".", "./cjs", "./esm", "./system", "./cjs/system" and "./esm/system", with types pointing at ./types/index.d.ts and ./types/system.d.ts. If you import from a subpath that is not in that map, the resolution will fail, and the README does not walk through which subpath to choose. The published files array is limited to cjs/*.cjs, esm/*.mjs and types/*.d.ts, so anything else in the repository is not in the tarball.

The third limitation is the one the README is candid about: performance claims come from a benchmark against Vue 3.4 and other frameworks, hosted in an external repository at transitive-bullshit/js-reactivity-benchmark. That is a single benchmark on someone else's harness. It is not a reason to distrust the project, but it is also not a substitute for measuring your own workload.

## How alien-signals differs from Preact Signals and Vue's reactivity package

The closest comparison is Preact Signals, and the README makes the relationship explicit by citing Preact's double-linked-list approach. The difference is in the pull direction. Preact's design is described in the linked blog post as a pull-based approach, and Vue 3.5 moved to a pull-based algorithm similar to Preact as well. alien-signals deliberately goes the other way, combining push and pull, and that combination is the research question the project exists to answer.

The practical difference for an adopter is what comes in the box. Preact Signals ships with Preact's ecosystem and a component integration story. alien-signals ships a core with no framework bindings at all, and the README's Derived Projects list is where bindings live. If you are already inside Vue, you do not need this package: the README states the core algorithm was ported into Vue 3.6, so the same propagation logic arrives through Vue itself. Choosing alien-signals only makes sense when you want the algorithm without the framework around it.

## Maintenance, licence and what upgrading costs

The repository is not archived, and the last push was on 2026-06-10. Releases are infrequent and version jumps are large: v1.0.0 in January 2025, v2.0.0 in April 2025, v3.2.0 in May 2026, with package.json sitting at 3.2.1. That cadence means you cannot count on a steady stream of patch releases, and a major bump can land after a long quiet period.

The licence is MIT, declared in package.json and present as a LICENSE file at the repository root. MIT permits commercial use and modification, and it requires that the copyright notice and permission notice be preserved in copies or substantial portions. That is the extent of what the repository supports saying; anything about your specific obligations belongs with your own legal review.

The upgrade cost is real because the package exposes six export subpaths and two type entry points. A major version can change the shape of the ./system entry independently of the main entry, and the README does not publish a migration guide for the v1 to v2 to v3 transitions. If you depend on the algorithmic core directly rather than the high-level API, pin the version and read the diff before moving.

## Conclusion

Adopt alien-signals if you want a small, framework-agnostic signal primitive and you are willing to read the source when the README runs out, which it does around cleanup and async. Do not adopt it if you need framework bindings, a documented API reference or a large community answering questions, because the README points to derived projects for bindings instead of shipping them. Before wiring it in, verify the exported surface in types/index.d.ts and types/system.d.ts, and run the repository's own test suite with pnpm test to confirm the build works in your environment.

## FAQ

### What is alien-signals?

It is a TypeScript signal library from StackBlitz that the README describes as an exploration of a push-pull based signal algorithm. It exports signal, computed, effect, effectScope and trigger, and the same core algorithm was ported into Vue 3.6.

### How do I install alien-signals from npm?

The homepage points at npmjs.com/package/alien-signals, so it installs with npm install alien-signals. The README's basic example then imports signal, computed and effect from the package root.

### Does alien-signals have React bindings?

Not in this package. The README's Derived Projects list points to Rajaniraiyn/react-alien-signals for React bindings and to gn8-ai/universe-alien-signals for use in modern frontend frameworks.

### Why does a computed value not update after I mutate a signal's array?

Because the signal setter was never called, so nothing propagated. The README's manual triggering example shows length() staying at 0 after arr().push(1) and updating only after trigger(arr) is called.

### How does alien-signals relate to Vue?

The README states the core algorithm was ported back into Vue 3.6, and that the author also wrote Vue's reactivity code. It also says the algorithm is used in vuejs/language-tools for incremental AST parsing and virtual code generation.

## Sources

- [License: MIT](https://github.com/stackblitz/alien-signals/blob/master/LICENSE)
- [Project website](https://npmjs.com/package/alien-signals)
- [README](https://github.com/stackblitz/alien-signals/blob/master/README.md)
- [Releases](https://github.com/stackblitz/alien-signals/releases)
- [stackblitz/alien-signals on GitHub](https://github.com/stackblitz/alien-signals)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/stackblitz-alien-signals
