Preact Signals Core

Fast, framework-agnostic reactive state primitives with automatic dependency tracking.

Library
npm
v1.14.4
4,475stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
86/100Excellent
Development Activity92
Maintenance100
Community56
Maturity56
Momentum40

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
86/100Excellent
Architecture90
Code Quality88
Innovation85
Learning Curve82

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.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search