Universal state management SDK for JavaScript and TypeScript
One reactive core. Three paradigms. Every framework.
StateLoom provides a signal-based reactive core with paradigm adapters (Store, Atom, Proxy) and framework adapters (React, Vue, Solid, Svelte, Angular). Pick the mental model you prefer, use it in any framework, and compose middleware for persistence, devtools, sync, and more.
- Signal-based core (~1.5 KB gzipped) -- push-pull hybrid reactivity aligned with the TC39 Signals proposal
- Three paradigms, one core -- Store (Zustand-style), Atom (Jotai-style), Proxy (Valtio-style) all built on the same signal graph
- Every major framework -- React, Vue, Solid, Svelte, Angular with thin, idiomatic adapters
- SSR-first -- per-request scope isolation prevents state leakage between server requests
- Composable middleware -- persistence, devtools, tab sync, history, telemetry as independent packages
- TypeScript-first -- strict types with full inference, no
any, no enums, named exports only - Tree-shakeable -- pay only for the packages you use
| Store | Atom | Proxy | |
|---|---|---|---|
| Mental model | Single object with actions | Bottom-up composition | Mutable syntax, immutable snapshots |
| Inspired by | Zustand, Redux Toolkit | Jotai, Recoil | Valtio, MobX |
| Best for | App-wide state with actions | Fine-grained, derived state | Rapid prototyping, mutable APIs |
| Middleware | Yes | No | No |
| Package | @stateloom/store |
@stateloom/atom |
@stateloom/proxy |
import { createStore } from '@stateloom/store';
const counterStore = createStore((set) => ({
count: 0,
increment: () => set((state) => ({ count: state.count + 1 })),
reset: () => set({ count: 0 }),
}));
counterStore.getState().increment();
console.log(counterStore.getState().count); // 1import { atom, derived } from '@stateloom/atom';
const countAtom = atom(0);
const doubledAtom = derived((get) => get(countAtom) * 2);
countAtom.set(5);
console.log(doubledAtom.get()); // 10import { observable, snapshot } from '@stateloom/proxy';
const state = observable({ count: 0, text: 'hello' });
state.count++;
const snap = snapshot(state);
console.log(snap.count); // 1import { signal, computed, effect } from '@stateloom/core';
const count = signal(0);
const doubled = computed(() => count.get() * 2);
effect(() => {
console.log(`Count is ${count.get()}, doubled is ${doubled.get()}`);
});
count.set(5); // logs: "Count is 5, doubled is 10"| Framework | Package | Adapter Pattern |
|---|---|---|
| React | @stateloom/react |
useSignal(), useStore(), ScopeProvider |
| Vue | @stateloom/vue |
useSignal(), useStore(), stateloomPlugin |
| Solid | @stateloom/solid |
useSignal(), useStore(), ScopeProvider |
| Svelte | @stateloom/svelte |
toReadable(), toWritable() |
| Angular | @stateloom/angular |
toAngularSignal(), injectStore(), toObservable() |
| Vanilla JS | @stateloom/core |
Direct signal/computed/effect API |
| Package | Description |
|---|---|
@stateloom/core |
Signal-based reactive primitives (signal, computed, effect, batch, scope) |
| Package | Description |
|---|---|
@stateloom/store |
Zustand-style store with actions and middleware support |
@stateloom/atom |
Jotai-style atomic state with derived atoms and atom families |
@stateloom/proxy |
Valtio-style proxy objects with structural sharing snapshots |
| Package | Description |
|---|---|
@stateloom/react |
React hooks and SSR scope provider |
@stateloom/vue |
Vue composables and plugin |
@stateloom/solid |
SolidJS primitives and scope context |
@stateloom/svelte |
Svelte readable/writable store adapters |
@stateloom/angular |
Angular signals, observables, and DI integration |
| Package | Description |
|---|---|
@stateloom/devtools |
Browser DevTools integration and logging middleware |
@stateloom/persist |
State persistence (localStorage, sessionStorage, IndexedDB, cookies) |
@stateloom/persist-redis |
Redis storage backend for @stateloom/persist |
@stateloom/history |
Undo/redo history middleware |
@stateloom/tab-sync |
Cross-tab state synchronization via BroadcastChannel |
@stateloom/immer |
Immer integration for immutable updates with mutable syntax |
@stateloom/telemetry |
State change telemetry and error tracking middleware |
@stateloom/server |
Server-side scope management with LRU caching |
@stateloom/testing |
Test utilities (mock stores, test scopes, value collectors) |
Install the core and the packages you need:
# Core + Store + React (most common setup)
pnpm add @stateloom/core @stateloom/store @stateloom/react
# Core + Atom (bottom-up composition)
pnpm add @stateloom/core @stateloom/atom
# Core + Proxy (mutable syntax)
pnpm add @stateloom/core @stateloom/proxy
# Add middleware as needed
pnpm add @stateloom/persist @stateloom/devtools- Getting Started -- set up StateLoom in your project
- API Reference -- per-package documentation
- Architecture -- design decisions and layer diagram
- Contributing -- how to contribute
| Example | Framework | Source |
|---|---|---|
| Vanilla JS | None | examples/vanilla-js |
| React + Vite | React 19 | examples/react-vite |
| Vue + Vite | Vue 3 | examples/vue-vite |
| Solid + Vite | SolidJS | examples/solid-vite |
| Svelte + Vite | Svelte 5 | examples/svelte-vite |
| Angular | Angular 19 | examples/angular |
| Next.js SSR | Next.js 15 | examples/nextjs-ssr |
We welcome contributions! See CONTRIBUTING.md for how to get started.
For detailed contributor documentation, see the Contributing Guide.
MIT