The Fragmentation Problem
Modern frontend development has a familiar pattern:
- Start with simple
useStatehooks - Need shared state? Add Context
- Context re-renders too much? Add a state manager
- State manager doesn’t handle async well? Add a data fetching library
- Need forms? Another library
- Routes need data loading? Router with loaders
- Persistence? Yet another library
- Logging and analytics? Here we go again...
Each tool has its own mental model, API quirks, and bundle cost. The stack grows, complexity multiplies, and new team members need weeks to understand it all. Versioning and maintaining compatibility across multiple libraries becomes a nightmare.
Reatom is a different approach. One coherent system that can handle all of these concerns — from the simple…
The Fragmentation Problem
Modern frontend development has a familiar pattern:
- Start with simple
useStatehooks - Need shared state? Add Context
- Context re-renders too much? Add a state manager
- State manager doesn’t handle async well? Add a data fetching library
- Need forms? Another library
- Routes need data loading? Router with loaders
- Persistence? Yet another library
- Logging and analytics? Here we go again...
Each tool has its own mental model, API quirks, and bundle cost. The stack grows, complexity multiplies, and new team members need weeks to understand it all. Versioning and maintaining compatibility across multiple libraries becomes a nightmare.
Reatom is a different approach. One coherent system that can handle all of these concerns — from the simplest counter to the most complex enterprise data flows. Use what you need, integrate with what you have.
For fast overview, you can check out our site: https://v1000.reatom.dev/
The Zen
Four principles guide Reatom’s design:
- Primitives outperform frameworks — A few powerful building blocks beat a complex framework
- Composition beats configuration — Stack simple pieces instead of configuring monoliths
- Explicit specifics, implicit generics — Be clear about what matters, hide the boilerplate
- Compatibility worth complexity — Works with your stack, not against it
These aren’t marketing slogans. They’re the result of six years of production use and continuous refinement, starting with the first LTS release in December 2019.
Start Simple
If signals are familiar, Reatom will feel natural:
import { atom, computed } from '@reatom/core'
const counter = atom(0)
const isEven = computed(() => counter() % 2 === 0)
// Read
console.log(counter()) // 0
console.log(isEven()) // true
// Write
counter.set(5)
counter.set((prev) => prev + 1)
No providers, no boilerplate, no ceremony. The core is less than 3KB gzipped — smaller than some "lightweight" alternatives.
You can stop there, but here’s where it gets interesting...
Grow Infinitely
The same primitives that power a counter can handle enterprise-grade complexity:
import { atom, computed, withAsyncData, withSearchParams } from '@reatom/core'
// Sync with URL search params automatically
const search = atom('', 'search').extend(withSearchParams('search'))
const page = atom(1, 'page').extend(withSearchParams('page'))
// Async computed with automatic cancellation
const searchResults = computed(async () => {
await wrap(sleep(300)) // The wrap provides debouncing here
const response = await wrap(fetch(`/api/search?q=${search()}&page=${page()}`))
return await wrap(response.json())
}, 'searchResults').extend(withAsyncData({ initState: [] }))
// Now you have:
searchResults.ready() // loading state
searchResults.data() // the results
searchResults.error() // any errors
What happens here:
searchandpageatoms automatically sync with URL params- The computed re-runs only when dependencies change AND when something subscribes to it (lazy!)
- If the user types faster than the API responds, previous requests are automatically cancelled
- Race conditions? Handled. Memory leaks? Impossible.
This is the same atom from the counter example — just extended.
The Extension System
Instead of a monolithic framework, Reatom provides composable extensions that stack cleanly:
const theme = atom('dark').extend(
// Persist to localStorage
withLocalStorage('theme'),
)
const list = atom([]).extend(
// Memoize an equal changes
withMemo(),
)
const unreadCount = atom(0).extend(
// React to state changes
withChangeHook((count) => {
document.title = count > 0 ? `(${count}) My App` : 'My App'
}),
// Sync across tabs
withBroadcastChannel('notificationsCounter'),
)
Each extension does one thing well. Compose exactly what’s needed.
Beyond State: Complete Solutions
Reatom provides full solutions for common frontend challenges:
Forms
Type-safe form management with first-class support for:
- Field-level and form-level validation (sync and async)
- Integration with Standard Schema validators (Zod, Valibot, etc.)
- Dynamic field arrays with add, remove, reorder operations
- Focus tracking, dirty detection, error management
- No weird string paths — just objects and atoms
- Extremely optimized and performant
https://v1000.reatom.dev/start/forms/
Routing
Type-safe routing with automatic lifecycle management:
- Parameter validation and transformation
- Data loading with automatic cancellation on navigation
- Nested routes with shared layouts
- Search parameter handling
- Isomorphic cross-framework support
- Factory pattern — state created in route loaders is automatically garbage collected on navigation, solving the "global state cleanup" problem
https://v1000.reatom.dev/start/routing/
Persistence
A ton of built-in storage adapters with general advanced features:
- localStorage, sessionStorage, BroadcastChannel, IndexedDB, Cookie and Cookie Store
- Integration with Standard Schema validators (Zod, Valibot, etc.)
- Version migrations for data format changes
- TTL (time-to-live) support
- Graceful fallback to memory storage when unavailable
https://v1000.reatom.dev/handbook/persist/
Deep Technical Advantages
Cause Tracking
Reatom emulates TC39 AsyncContext and gets a TON of benefits from it:
- Automatic cancellation of concurrent asynchronous chains (kinda debounce): https://v1000.reatom.dev/handbook/async-context/
- Some sort of IoC and DI possible: https://v1000.reatom.dev/reference/methods/#variable-1
- Async transactions: https://v1000.reatom.dev/reference/methods/#withrollback
- Process tracking and logging: https://v1000.reatom.dev/start/tooling/
The last feature is a game changer for complex async flows. You can easily inspect the cause of your concurrent operations and reduce debugging time from hours to minutes.
Performance
Reatom has the best possible performance given its feature set. The more complex the application, the faster Reatom performs compared to alternatives.
Benchmarks for complex computations show Reatom outperforming MobX in moderately sized dependency graphs — impressive given that Reatom uses immutable data structures and operates in a separate async context, features that bring significant benefits but typically add overhead.
Explicit Reactivity, No Proxies
Proxy-based reactivity can be convenient for simple cases but becomes harder to trace in large codebases. With Reatom, hover over any property for a type hint — it’s always clear what’s reactive.
Reatom encourages atomization — transforming backend DTOs into application models where mutable properties become atoms:
// Backend DTO
type UserDto = { id: string; name: string }
// Application model with explicit reactivity
type User = { id: string; name: Atom<string> }
const userModel = { id: dto.id, name: atom(dto.name) }
// Now it's always clear:
userModel.id // static value — no reactivity
userModel.name() // reactive — tracks changes
This pattern gives you fine-grained control: define reactive elements precisely where needed, avoid the uncontrolled creation of observers, and never need toJS-like conversions to inspect or pass data.
Less complexity with atomization
In immutable state managers, updating one item in a list requires recreating the entire array — O(n) complexity. Reatom’s atomization pattern provides O(1) updates:
// Traditional immutable approach: O(n)
const updateName = (state, idx, name) => ({
...state,
users: state.users.map((u, i) => (i === idx ? { ...u, name } : u)),
})
// Reatom with atomization: O(1)
users()[idx].name.set(newName)
For lists with thousands of items, this difference matters.
Framework Agnostic, Ecosystem Friendly
Right now Reatom works best with React (https://v1000.reatom.dev/reference/react), but we already have draft packages for Vue, Preact, Solid, and Lit, with plans for Svelte and Angular (signals). You can also bind any library using reatomObservable.
Write your state and effects once, get a reusable model for complex tests and any view framework. Perfect for modularity in general, and microfrontends especially.
Reatom isn’t a walled garden. It plays well with the native web APIs and the entire npm ecosystem: use Zod for validation, any fetch wrapper for HTTP, use built-in AbortController’s, bind any UI library for components. Adopt Reatom incrementally in existing projects — no need to rewrite everything at once.
Try It
npm install @reatom/core @reatom/react
Start with atoms. Add extensions as needed. Scale to any complexity.
Links: