Preact Signals Core
Fast, framework-agnostic reactive state primitives with automatic dependency tracking.
Repository Health
Technical Analysis
Preact Signals Core is the framework-independent heart of the Preact Signals project, providing a tiny set of reactive primitives — signals, computed values, and effects — for modeling application state. Values are held in signal containers that automatically track which computeds and effects read them, so updates propagate only to the code that actually depends on the changed data.
Because the core carries no framework bindings, it can power reactivity in any JavaScript environment, from vanilla apps to custom UI layers. Signals are lazy by default: computeds and effects only recompute when something subscribes to them, keeping updates minimal without manual selectors or memoization.
What You Get
- A signal() primitive that stores a value and tracks every reader as a subscriber
- computed() for lazily derived values that recompute only when their dependencies change
- effect() for running side effects that re-execute when tracked signals update
- batch() and untracked() helpers for grouping writes and reading without subscribing
- A tiny, dependency-free, tree-shakeable bundle with full TypeScript types
Common Use Cases
- Powering reactive state in framework bindings such as @preact/signals and @preact/signals-react
- Building custom reactive UI layers or rendering engines outside of Preact
- Modeling derived application state without manual memoization or selectors
- Sharing observable state across modules in vanilla JavaScript apps
Under The Hood
Architecture - The entire core lives in a single ~1,100-line src/index.ts that implements a push-pull reactive graph. Signals hold a value plus a linked list of subscriber nodes; computeds and effects are nodes that record which signals they read during evaluation, forming a dependency graph that is re-linked on every run so stale edges are dropped. A global version counter and per-node flags let the library skip recomputation when nothing an observer depends on has actually changed.
Tech Stack - Written in TypeScript with zero runtime dependencies, built with microbundle and mangled via a shared mangle.json for minimal output. The monorepo is managed with pnpm workspaces and tested with Vitest; the core ships ESM, CJS, and UMD builds with generated type declarations.
Code Quality - The implementation is dense but deliberate, using bit flags and manual linked lists for performance rather than convenience. It is covered by an extensive signal.test.tsx suite exercising batching, cycles, lazy evaluation, and unsubscribe edge cases, and the public surface is small and fully typed.
API Design - The public API is intentionally minimal — signal, computed, effect, batch, untracked — and reads like built-in primitives. State is accessed through a plain .value property and dependencies are tracked implicitly, so getting started requires almost no boilerplate and no configuration.
Used by 2 apps in this directory
AFFiNE
Productivity · Project Management · Note Taking
Write, draw, and plan in one infinite canvas — the open-source alternative to Notion and Miro that keeps your data yours.
Orama
Search · Developer Tools
A complete, embeddable search engine and RAG pipeline running in browsers, servers, and edge networks with full-text, vector, and hybrid search in under 2KB.