legend-state
@legendapp/state is a modern state management library built for JavaScript applications, with first-class React support. It uses proxy-based observables to provide fine-grained reactivity where components re-render only when their specific data changes, not when unrelated parts of the state tree update. This approach eliminates the need for selectors, memoization boilerplate, or manual dependency tracking.
The library was created to solve performance bottlenecks in complex React applications while drastically reducing code verbosity. Unlike traditional state managers that require actions, reducers, or context providers, Legend-State lets you directly mutate observable objects with automatic tracking. At just 4kb gzipped, it includes batteries-included features like local persistence (LocalStorage, IndexedDB, MMKV) and remote synchronization (REST APIs, Firebase, TanStack Query) without additional plugins.
Developers building data-intensive applications, offline-first mobile apps, or real-time collaborative tools adopt Legend-State for its sync engine capabilities. The library handles optimistic updates, conflict resolution, differential syncing, and automatic retries out of the box. It's particularly popular in React Native projects where bundle size and render performance are critical. The TypeScript-first design provides complete type inference across nested observable structures.
Version 2.1.15 represents a mature implementation with stable APIs for both simple local state and complex distributed systems. The library works seamlessly with React Server Components and the new React Compiler, making it future-proof for modern React architectures.
import { observable } from '@legendapp/state';
import { observer, useSelector } from '@legendapp/state/react';
import { ObservablePersistLocalStorage } from '@legendapp/state/persist-plugins/local-storage';
import { syncedFetch } from '@legendapp/state/sync-plugins/fetch';
// Create observable with automatic persistence and API sync
const todos$ = observable(
syncedFetch({
get: 'https://jsonplaceholder.typicode.com/todos',
set: async ({ value }) => {
await fetch('https://jsonplaceholder.typicode.com/todos', {
method: 'POST',
body: JSON.stringify(value),
headers: { 'Content-Type': 'application/json' }
});
},
persist: {
plugin: ObservablePersistLocalStorage,
name: 'todos'
}
})
);
// Observer component re-renders only when its specific todo changes
const TodoItem = observer(({ id }) => {
const todo = todos$[id];
return (
<div>
<input
type="checkbox"
checked={todo.completed.get()}
onChange={(e) => todo.completed.set(e.target.checked)}
/>
<input
value={todo.title.get()}
onChange={(e) => todo.title.set(e.target.value)}
/>
</div>
);
});
// Hook-based approach with selector for computed values
function TodoStats() {
const completed = useSelector(() =>
Object.values(todos$.get()).filter(t => t.completed).length
);
return <span>Completed: {completed}</span>;
}
// Direct mutations sync automatically to localStorage and API
function addTodo(title) {
const newId = Date.now();
todos$[newId].set({
id: newId,
title,
completed: false
});
}Offline-first mobile applications: Use the built-in persistence and sync plugins to create React Native apps that work without connectivity. Changes are queued locally in MMKV storage, then automatically synced to your backend when connection restores, with conflict resolution and retry logic included.
Real-time collaborative editing: Build document editors or collaborative whiteboards where multiple users' changes need to sync. The observable system tracks granular changes (which specific fields changed), enabling efficient delta updates instead of full document replacement.
Complex form state with auto-save: Manage deeply nested form data with computed validations that only recalculate affected fields. Persist drafts to localStorage automatically and sync final submissions to REST APIs, all with a few configuration lines instead of custom debouncing and error handling.
Dashboard applications with live data: Create admin panels or analytics dashboards that fetch from multiple endpoints. Observables can integrate with TanStack Query for server state while maintaining local UI state, with automatic re-fetching and optimistic updates when users edit data.
Shopping carts with persistence: Implement cart state that survives page refreshes and syncs across devices. The library handles serialization, storage in IndexedDB, and merging cart data when users log in, without writing custom synchronization code.
👻 Primitive and flexible state management for React
Predictable state container for JavaScript apps
Hooks for managing, caching and syncing asynchronous and remote data in React
🧙 Valtio makes proxy-state simple for React and Vanilla
🐻 Bear necessities for state management in React
npm install @legendapp/statepnpm add @legendapp/statebun add @legendapp/state