A tiny (265 bytes) state manager for React/Preact/Vue/Svelte with many atomic tree-shakable stores
Nanostores is a minimalist state management library weighing just 265 bytes (minified and brotlied) that provides atomic, tree-shakable stores for JavaScript applications. Unlike monolithic state managers, it uses many small stores instead of a single global store, allowing each store to be independently imported and only bundled when actually used. This architectural choice makes it ideal for applications where bundle size matters or when mixing multiple frameworks in a single project.
The library supports all major frameworks through dedicated integration packages (@nanostores/react, @nanostores/vue, etc.) while maintaining zero dependencies in its core. Stores are lazy by default—they only activate when components subscribe to them and automatically disable when all listeners disconnect. This lazy behavior prevents unnecessary resource consumption from background timers, network listeners, or computations when the data isn't being used.
With over 1.4 million weekly downloads, Nanostores has gained adoption in multi-framework environments like Astro projects where different UI islands may use different frameworks but need to share state. Its TypeScript-first design provides strong typing out of the box, and its atom/computed model makes it straightforward to derive state without manual dependency tracking. The ecosystem includes extensions for localStorage persistence, routing, internationalization, and remote data fetching.
Nanostores excels in scenarios where Redux feels too heavy, when you need state sharing across framework boundaries, or when building component libraries that shouldn't dictate a specific state solution. It moves business logic out of components into stores while keeping the implementation simple and the runtime cost minimal.
import { atom, computed, map } from 'nanostores';
import { useStore } from '@nanostores/react';
// Atom for simple state
export const $isAuthenticated = atom(false);
// Map store for structured data
export const $currentUser = map({
id: null,
name: '',
role: 'guest'
});
// Computed store (derived state)
export const $canEditContent = computed(
[$isAuthenticated, $currentUser],
(isAuth, user) => isAuth && ['admin', 'editor'].includes(user.role)
);
// Actions that modify stores
export function login(userId, userName, userRole) {
$isAuthenticated.set(true);
$currentUser.setKey('id', userId);
$currentUser.setKey('name', userName);
$currentUser.setKey('role', userRole);
}
export function logout() {
$isAuthenticated.set(false);
$currentUser.set({ id: null, name: '', role: 'guest' });
}
// React component usage
function EditorToolbar() {
const canEdit = useStore($canEditContent);
const user = useStore($currentUser);
return (
<div>
<h2>Welcome, {user.name}</h2>
{canEdit ? (
<button onClick={() => console.log('Editing...')}>Edit</button>
) : (
<p>View-only access</p>
)}
</div>
);
}
// Can also subscribe in vanilla JS
$isAuthenticated.listen((value) => {
console.log('Auth status changed:', value);
});Multi-framework Astro applications: When building an Astro site with React islands for interactive forms, Vue components for data tables, and Svelte widgets, Nanostores provides a unified state layer that all frameworks can consume without compatibility issues or redundant bundle bloat.
Component library state management: Library authors can use Nanostores to manage internal state without forcing consumers to adopt Redux or another heavy framework-specific solution, since stores work universally and compile down to vanilla JavaScript subscriptions.
Mobile-first web applications: Apps targeting low-end devices or slow networks benefit from the tiny bundle size and tree-shaking—only importing user authentication stores won't bundle the shopping cart or analytics stores, keeping initial payloads minimal.
Cross-tab synchronization: Using @nanostores/persistent, applications can persist user preferences, draft forms, or authentication tokens to localStorage with automatic synchronization across browser tabs, useful for multi-tab workflows like email clients or admin dashboards.
Performance-critical dashboards: Real-time dashboards with many widgets can use atomic stores per widget or data stream, ensuring updates to one chart don't trigger re-renders in unrelated components, unlike single-store solutions where selector functions run on every state change.
👻 Primitive and flexible state management for React
Recoil - A state management library for React
Predictable state container for JavaScript apps
🧙 Valtio makes proxy-state simple for React and Vanilla
🐻 Bear necessities for state management in React
npm install nanostorespnpm add nanostoresbun add nanostores