From Zustand to Reactive Orchestration
Legacy TypeScript website content. Shared public website, blog, protocol, guide, and language-neutral docs ownership now lives in
~/src/graphreflyunder D563. This page is retained here only as migration/reference material while the TS API generator still lives inwebsite/.
From Zustand to Reactive Orchestration
Section titled “From Zustand to Reactive Orchestration”Chronicle 25 — Arc 7: From Library to Platform
Most teams cannot rewrite state architecture in one sprint.
That is why GraphReFly ships compatibility wrappers: start with familiar store ergonomics, then progressively adopt richer reactive orchestration without breaking app code.
Migration reality
Section titled “Migration reality”A typical Zustand codebase already has:
- centralized store setup
- selector-driven reads
- imperative action methods
Asking teams to jump directly into node, derived(), and graph.describe() is a non-starter. The wrapper strategy meets them where they are.
What the wrapper does
Section titled “What the wrapper does”The clean-slate store facade zustandStore(...) from @graphrefly/ts/adapters maps caller-owned GraphReFly nodes into a Zustand-style shape:
import { zustandStore } from '@graphrefly/ts/adapters';
const useStore = createStore((set) => ({ count: 0, increment: () => set((s) => ({ count: s.count + 1 })),}));Under the hood:
- Zustand-style creation APIs map to
state()andderived()nodes - selectors and subscriptions map to reactive node subscriptions
- actions remain explicit mutation boundaries via
set()
Teams now get graph-aware propagation and composable lifecycle signals without changing a line of component code.
Why this is more than syntax sugar
Section titled “Why this is more than syntax sugar”The key upgrade is architectural:
- from isolated state slices to connected dataflow through the reactive graph
- from ad hoc async logic to orchestrated reactive pipelines via
producer()andeffect() - from opaque updates to inspectable graph behavior via
graph.describe()
You keep adoption friction low while changing what is possible.
Practical rollout pattern
Section titled “Practical rollout pattern”Successful migrations usually follow:
- Bind existing state nodes through
zustandStore(...)from@graphrefly/ts/adapters - Keep existing actions/selectors stable — components do not change
- Move async flows into reactive operators and orchestration nodes
- Gradually replace wrapper surfaces with native
state(),derived(), andeffect()where beneficial - Use
graph.describe()to verify the reactive topology matches expectations
This lets teams de-risk gradually and measure value at each step.
The Trojan horse
Section titled “The Trojan horse”The compat wrapper is deliberately a Trojan horse. Once teams have GraphReFly running under familiar Zustand APIs, the reactive graph is already there — connected, inspectable, orchestratable. The shift from “Zustand with extra steps” to “reactive orchestration platform” happens incrementally as teams discover what the graph enables: cross-store derivations, lifecycle-aware effects, observable control flow.
In the predecessor (callbag-recharge), we proved this strategy worked. GraphReFly carries it forward with a cleaner primitive foundation — one node instead of five separate primitives means the compat layer has less internal mapping to do.
Takeaway
Section titled “Takeaway”Compatibility is not compromise when it is designed as a bridge.
For GraphReFly, wrappers are a platform strategy: reduce migration pain now, unlock orchestration capability later. The team that starts with createStore today is the team running full reactive orchestration next quarter.