valtio

Proxy-based state management for React and vanilla JavaScript with automatic render optimization.

Library
npm
v2.3.2
10,231stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
73/100Good
Development Activity64
Maintenance64
Community64
Maturity60
Momentum40

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
90/100Excellent
Architecture88
Code Quality92
Innovation85
Learning Curve95

Valtio is a proxy-based state management library from the pmndrs (Poimandres) ecosystem, the same team behind Zustand and React Three Fiber. It turns a plain JavaScript object into a self-aware proxy: you mutate it directly with normal assignment (state.count++) instead of dispatching actions or calling setters, and Valtio tracks exactly which properties change.

For React, the useSnapshot hook subscribes a component to an immutable snapshot of that proxy and layers a second read-tracking proxy on top of it, so the component only re-renders when a property it actually accessed during render has changed, with no selectors, memoized comparators, or reducers required. The same core works outside React too: valtio/vanilla exposes proxy, subscribe, and snapshot directly for use in plain JS, Node, or any other renderer, with an optional valtio/utils layer adding proxyMap, proxySet, subscribeKey, watch, and Redux DevTools integration.

What You Get

  • proxy() core - wraps any object in a mutation-tracking Proxy; nested objects become their own independently tracked proxies automatically.
  • useSnapshot hook - subscribes a React component to a read-tracked, render-optimized snapshot via useSyncExternalStore, so only accessed paths trigger re-renders.
  • Vanilla-only entry point - valtio/vanilla exposes proxy/subscribe/snapshot with zero React dependency for use in Node, vanilla JS, or non-React renderers.
  • Utility belt - valtio/utils adds proxyMap, proxySet, subscribeKey, watch, deepClone, and Redux DevTools integration on top of the core primitives.
  • Computed properties - plain object getters work directly on proxied state without any special API.
  • Unstable internal hooks - unstable_replaceInternalFunction lets advanced users swap internals (objectIs, newProxy, canProxy, createSnapshot) for custom tracking behavior.

Common Use Cases

  • Global app state without boilerplate - replace Redux-style actions/reducers with direct mutation (state.count++) while keeping fine-grained re-render optimization.
  • Cross-component state outside React - mutate and read a shared proxy from event handlers, WebSocket callbacks, or other non-component code, then let useSnapshot sync the UI automatically.
  • Large nested state trees - because every nested object is independently proxied, deeply nested state (e.g. a form or document model) can be subscribed to at any granularity without re-render cascades.
  • Non-React or multi-renderer apps - use the same proxy/subscribe/snapshot API in vanilla JS, react-native, or react-three-fiber via the framework-agnostic vanilla entry point.
  • Debugging state changes - hook into Redux DevTools via the devtools util to inspect and time-travel through proxy state changes during development.

Under The Hood

Architecture Valtio separates concerns cleanly across three layers: a framework-agnostic core in src/vanilla.ts that implements proxy(), subscribe(), and snapshot() using native JS Proxy plus WeakMap-based state tracking (proxyStateMap, versionHolder, snapCache) with a nested-proxy composition model where child proxies propagate change notifications to parents via propProxyStates listener chains; a React binding layer in src/react.ts (useSnapshot) built on useSyncExternalStore that layers a second proxy-compare-based tracking proxy on top of vanilla snapshots purely for read-access tracking, decoupling mutation tracking from usage tracking; and a utils layer (src/vanilla/utils/, src/react/utils/) of optional helpers (proxyMap, proxySet, subscribeKey, watch, devtools, deepClone, useProxy) that compose on top of the core primitives rather than modifying them. The unstable_replaceInternalFunction escape hatch shows the core was deliberately designed for extension without forking, though every util and the React binding still depend directly on the shared proxyStateMap/ensureVersion/addListener internals.

Tech Stack Strict TypeScript throughout (isolatedDeclarations, exactOptionalPropertyTypes, noUncheckedIndexedAccess) with a single runtime dependency, proxy-compare (from the same author), and react declared only as an optional peer dependency. Built with Rollup and esbuild into separate CJS/ESM bundles per entry point (index, vanilla, utils, react, react/utils), tested with Vitest plus jsdom and Testing Library, linted with an ESLint 9 flat config and typescript-eslint, formatted with Prettier, and organized as a pnpm workspace with examples and a documentation site as separate workspace members. No server framework or database involved; this ships purely as a dual CJS/ESM runtime library.

Code Quality An extensive test suite spans React hooks, vanilla proxy behavior, every util, dedicated regression cases for past bugs, a memory-leak test, and a benchmark suite, all run through Vitest with v8 coverage reporting. TypeScript strictness is pushed further than typical library defaults, and CI runs type-checking, linting, formatting, and spec tests as separate gated steps. Error handling is intentionally minimal (a synchronous throw on non-object input to proxy()), which is appropriate for a low-level primitive rather than an application framework.

API Design The public surface is deliberately small: three vanilla exports (proxy, subscribe, snapshot) cover the entire core, and useSnapshot is the only hook most React consumers need, with state read and written through plain property access and assignment rather than a custom action/reducer DSL. Naming stays consistent across entry points (proxy, proxySet, proxyMap all share the same prefix), documentation comments sit on every public export with runnable examples, and the README surfaces non-obvious gotchas (this-binding, snapshot-reference identity) up front rather than leaving newcomers to discover them. The main cost to a beginner is conceptual rather than syntactic: understanding the split between a mutable proxy and its read-only snapshot takes a moment, which the maintainers acknowledge directly and soften with the simplified useProxy util.

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