Skip to content

Reactivity & Atom

The reactivity modules give Effect a small, framework-agnostic reactive state system. You declare values as atoms, and an AtomRegistry evaluates them, caches results, tracks which atoms depend on which, runs the effects and streams they describe, and disposes nodes once nothing observes them.

An Atom does not hold a value. It describes how to read one. The registry is the runtime owner of the actual cache:

  • Reading an atom (registry.get(atom)) creates or reuses a node, evaluates the atom if its value is missing or stale, and records any nested reads as dependency edges.
  • Calling get(other) inside an atom’s read function creates a dependency edge. When other changes or refreshes, every dependent atom is invalidated and re-read on demand.
  • Writing a writable atom updates its node, invalidates dependents, and notifies subscribers after the current batch settles.
  • A node lives as long as something observes it (a subscription, a scoped mount, or a dependent child). When the last observer disappears, non-keepAlive atoms can be disposed immediately or after their idle TTL, which also runs finalizers and may rebuild derived values on the next read.

Because the cache lives in the registry, the same atom object can hold different values in different registries. Use a separate registry per UI root, request, test, or route boundary that needs isolated state.

import { Atom, AtomRegistry } from "effect/unstable/reactivity"
const count = Atom.make(0)
const doubled = Atom.make((get) => get(count) * 2)
const registry = AtomRegistry.make()
registry.set(count, 21)
registry.get(doubled)
// 42

doubled never recomputes on its own — it recomputes the next time it is read after count has been invalidated by the set.

Atom

Declare reactive values: synchronous state, derived reads, effects, streams, command-style functions, and persisted/URL-backed state. Read more →

AtomRegistry

The runtime that owns the node graph: evaluates reads, caches values, tracks dependencies, and disposes unobserved nodes. Read more →

AsyncResult

The value an effectful or async atom produces: Initial, Success, or Failure, each with a waiting flag. Read more →

Reactivity

Key-based invalidation that connects writes to dependent reads — queues, streams, and mutations keyed by application data. Read more →

AtomRef

Local mutable cells and SSR hydration helpers for moving server-computed atom values to the client. Read more →

Server state

Bind atoms to a server via RPC (AtomRpc) or an HTTP API (AtomHttpApi). Read more →