State management that works everywhere, at lightning speed
1.7-45x faster • 1.45 kB gzipped • Framework agnostic • 100% Type-safe
Zen is a hyper-optimized state management library that delivers signal-like performance across all major frameworks. Through extreme minimalism and architectural excellence, Zen achieves speeds that crush the competition while keeping your bundle microscopic.
Stop settling for framework lock-in. Choose Zen.
# Using bun (recommended)
bun add @sylphx/zen
# Using npm
npm install @sylphx/zen
# Using pnpm
pnpm add @sylphx/zen
# Using yarn
yarn add @sylphx/zen
import { zen, get, set, subscribe } from '@sylphx/zen';
// Create reactive state
const count = zen(0);
// Subscribe to changes
subscribe(count, (value) => {
console.log('Count:', value);
});
// Update state
set(count, get(count) + 1);
import { zen, set } from '@sylphx/zen';
import { useStore } from '@sylphx/zen-react'; // 216 bytes
const count = zen(0);
function Counter() {
const value = useStore(count);
return <button onClick={() => set(count, value + 1)}>{value}</button>;
}
<script setup>
import { zen, set } from '@sylphx/zen';
import { useStore } from '@sylphx/zen-vue'; // ~200 bytes
const count = zen(0);
const value = useStore(count);
</script>
<template>
<button @click="set(count, value + 1)">{{ value }}</button>
</template>
import { zen, set } from '@sylphx/zen';
import { useStore } from '@sylphx/zen-solid'; // 234 bytes
const count = zen(0);
function Counter() {
const value = useStore(count);
return <button onClick={() => set(count, value() + 1)}>{value()}</button>;
}
<script>
import { zen, set } from '@sylphx/zen';
import { fromZen } from '@sylphx/zen-svelte'; // 167 bytes
const count = zen(0);
const value = fromZen(count);
</script>
<button on:click={() => set(count, $value + 1)}>{$value}</button>
zen(initialValue)Create a reactive atom:
import { zen, get, set } from '@sylphx/zen';
const count = zen(0);
const user = zen({ name: 'Alice', age: 25 });
// Read value
console.log(get(count)); // 0
// Update value
set(count, 5);
set(user, { name: 'Bob', age: 30 });
computed(dependencies, computeFn)Create derived state:
import { zen, computed, set } from '@sylphx/zen';
const count = zen(10);
const doubled = computed([count], (n) => n * 2);
console.log(get(doubled)); // 20
set(count, 15);
console.log(get(doubled)); // 30
select(store, selector)Optimized single-source derivation (10-40% faster than computed):
import { zen, select, set } from '@sylphx/zen';
const user = zen({ name: 'Alice', age: 25 });
const userName = select(user, (u) => u.name);
console.log(get(userName)); // 'Alice'
set(user, { name: 'Bob', age: 30 });
console.log(get(userName)); // 'Bob'
subscribe(store, listener)Listen to state changes:
import { zen, set, subscribe } from '@sylphx/zen';
const count = zen(0);
const unsubscribe = subscribe(count, (value) => {
console.log('Count changed:', value);
});
set(count, 5); // Output: Count changed: 5
unsubscribe(); // Stop listening
map(initialObject)Create reactive object with key subscriptions:
import { map, setKey, listenKeys } from '@sylphx/zen';
const user = map({ name: 'Alice', age: 30 });
// Listen to specific keys
listenKeys(user, ['age'], (value) => {
console.log('Age changed:', value);
});
setKey(user, 'age', 31); // Output: Age changed: 31
setKey(user, 'name', 'Bob'); // No output (not listening to 'name')
deepMap(initialObject)Create reactive object with path subscriptions:
import { deepMap, setPath, listenPaths } from '@sylphx/zen';
const settings = deepMap({
user: { preferences: { theme: 'light' } },
data: [10, 20, 30]
});
// Listen to nested paths
listenPaths(settings, [['user', 'preferences', 'theme']], (value) => {
console.log('Theme:', value);
});
setPath(settings, 'user.preferences.theme', 'dark');
// Output: Theme: dark
setPath(settings, ['data', 1], 25); // Update array element
karma(asyncFunction, options)Create a fully reactive async store inspired by Riverpod AsyncProvider. Karma provides automatic caching, concurrent request deduplication, and reactive invalidation:
import { karma, runKarma, subscribeToKarma, karmaCache } from '@sylphx/zen';
// Create karma with options
const fetchUser = karma(
async (id: number) => {
const res = await fetch(`/api/users/${id}`);
return res.json();
},
{
cacheKey: (id) => ['user', id], // Custom cache key
staleTime: 5000, // 5s before stale
cacheTime: 30000, // 30s before auto-dispose
keepAlive: false // Auto-dispose when no listeners
}
);
// Execute and cache (36x faster on cache hits!)
const user1 = await runKarma(fetchUser, 123); // Fetches
const user2 = await runKarma(fetchUser, 123); // Returns cache instantly
// Subscribe to reactive updates
const unsub = subscribeToKarma(fetchUser, [123], (state) => {
if (state.loading) console.log('Loading...');
if (state.data) console.log('User:', state.data);
if (state.error) console.log('Error:', state.error);
});
// Reactive cache control
karmaCache.invalidate(fetchUser, 123); // Triggers re-fetch for active listeners
karmaCache.set(fetchUser, [123], newData); // Optimistic update
karmaCache.get(fetchUser, 123); // Get cached state
Key Features:
Performance:
See BENCHMARK_RESULTS.md for detailed benchmarks.
batch(fn)Batch multiple updates into a single notification:
import { zen, set, batch, subscribe } from '@sylphx/zen';
const count = zen(0);
const user = zen({ name: 'Alice' });
subscribe(count, () => console.log('Count updated'));
batch(() => {
set(count, 1);
set(count, 2);
set(count, 3);
});
// Output: Count updated (only once)
import { zen, onStart, onStop, onSet, onNotify, onMount } from '@sylphx/zen';
const count = zen(0);
// Called when first subscriber attaches
onStart(count, () => {
console.log('First subscriber');
});
// Called when last subscriber detaches
onStop(count, () => {
console.log('No more subscribers');
});
// Called before value changes
onSet(count, (newValue, oldValue) => {
console.log('Value changing:', oldValue, '->', newValue);
});
// Called after notifications sent
onNotify(count, () => {
console.log('Subscribers notified');
});
// Called once on store initialization
onMount(count, () => {
console.log('Store mounted');
});
For complex state updates, use @sylphx/zen-craft - a Zen integration powered by Craft, our in-house high-performance immer replacement:
import { zen } from '@sylphx/zen';
import { craftZen } from '@sylphx/zen-craft';
const todos = zen([
{ id: 1, text: 'Learn Zen', done: false }
]);
// Craft-powered immutable updates with JSON Patches support
craftZen(todos, (draft) => {
draft[0].done = true;
draft.push({ id: 2, text: 'Build app', done: false });
});
Why Craft?
Zen doesn't just compete - it dominates.
Through extreme minimalism and hyper-optimization, Zen achieves performance that crushes the competition while keeping your bundle microscopic.
All results in operations per second (higher is better):
| Operation | Zen | Zustand | Jotai | Nanostores | Valtio | Effector |
|---|---|---|---|---|---|---|
| Creation | 18.5M 🏆 | 16.7M | 10.7M | 2.6M | 0.6M | 24.7k |
| Get | 16.9M | 22.4M | 17.0M | 12.7M | 18.8M | 22.9M |
| Set (No Listeners) | 13.7M 🏆 | 9.6M | 1.6M | 10.5M | 3.4M | 3.2M |
Zen's atom creation is 45x faster than Jotai and 750x faster than Effector!
| Operation | Zen | Jotai | Nanostores | Zustand | Effector |
|---|---|---|---|---|---|
| Creation | 22.6M 🏆 | 13.7M | 0.4M | - | 6.7k |
| Get | 19.5M | 19.0M | 2.3M | 20.4M | 19.7M |
| Update Propagation | 8.0M | 0.2M | 8.9M | 8.1M | 0.6M |
Zen's computed creation is 56x faster than Nanostores and 3,400x faster than Effector!
| Operation | Zen | Nanostores |
|---|---|---|
| DeepMap Creation | 13.7M 🏆 | 2.5M |
| setPath (Shallow) | 2.8M 🏆 | 1.0M |
| setPath (1 Level) | 2.0M 🏆 | 0.8M |
| setPath (2 Levels) | 2.1M 🏆 | 0.7M |
| setPath (Array) | 3.9M 🏆 | 0.5M |
Zen wins across ALL nested state operations!
Benchmarks from latest version on Apple M1 Pro. Results may vary.
| Library | Size (Brotli + Gzip) | Notes |
|---|---|---|
| Zen (atom only) | 786 B | Minimal core |
| Zen (full) | 1.45 kB | All features |
| Jotai (atom) | 170 B | Atom only |
| Nanostores (atom) | 265 B | Atom only |
| Zustand (core) | 461 B | Core only |
| Valtio | 903 B | Full library |
| Effector | 5.27 kB | Full library |
| Redux Toolkit | 6.99 kB | Full library |
Zen delivers a complete state management solution with multiple patterns (atoms, maps, deepMaps, computed, karma) in just 1.45 kB - smaller than most libraries' core functionality!
cd packages/zen
bun run bench
See the difference with your own eyes!
Framework-specific state solutions lock you in:
// ❌ Solid Signals - Solid.js ONLY
const [count, setCount] = createSignal(0);
// ❌ Vue Reactivity - Vue ONLY
const count = ref(0);
// ❌ Svelte Stores - Svelte ONLY
const count = writable(0);
// ✅ Write your state logic ONCE
// state/counter.ts - Framework agnostic!
import { zen, computed } from '@sylphx/zen';
export const count = zen(0);
export const doubled = computed([count], (n) => n * 2);
Use the same state in ANY framework by swapping one import:
// React
import { useStore } from '@sylphx/zen-react';
// Vue
import { useStore } from '@sylphx/zen-vue';
// Solid.js
import { useStore } from '@sylphx/zen-solid';
// Svelte
import { fromZen } from '@sylphx/zen-svelte';
// Preact
import { useStore } from '@sylphx/zen-preact';
Same logic. Different frameworks. Zero rewrites.
| Feature | Zen | Zustand |
|---|---|---|
| Atom Creation | 1.11x faster | Baseline |
| Set (No Listeners) | 1.43x faster | Baseline |
| Computed Values | Built-in | Via middleware |
| Framework Support | 5 frameworks | React focused |
| Bundle Size (full) | 1.45 kB | 461 B (core only) |
| Deep State | Built-in deepMap | Manual |
| Async State | Built-in karma | Manual |
| Feature | Zen | Jotai |
|---|---|---|
| Atom Creation | 45x faster 🚀 | Baseline |
| Set (No Listeners) | 8.5x faster | Baseline |
| Framework Support | 5 frameworks | React focused |
| Bundle Size (full) | 1.45 kB | 170 B (atom only) |
| Feature | Zen | Nanostores |
|---|---|---|
| Computed Creation | 56x faster 🚀 | Baseline |
| DeepMap Creation | 5.5x faster | Baseline |
| setPath Operations | 2.5-7.8x faster | Baseline |
| Framework Support | 5 frameworks | 10+ frameworks |
| Bundle Size (full) | 1.45 kB | 265 B (atom only) |
Why settle for single-pattern libraries when you can have the complete package?
| Feature | Zen Karma | TanStack Query | SWR |
|---|---|---|---|
| Cache Hit Speed | 0.04ms 🏆 | ~1ms | ~1ms |
| Concurrent Deduplication | 100% effective | ✅ Yes | ✅ Yes |
| Framework Support | 5 frameworks | React, Vue, Solid, Svelte | React focused |
| Bundle Size | Included in 1.45 kB | 13.4 kB | 4.6 kB |
| Reactive Invalidation | ✅ Built-in | ✅ Built-in | ✅ Built-in |
| Stale-While-Revalidate | ✅ Built-in | ✅ Built-in | ✅ Built-in |
| Auto-Dispose | ✅ Configurable | ✅ Built-in | ✅ Built-in |
| Learning Curve | Minimal (same API as other Zen patterns) | Moderate | Moderate |
Karma is already included in Zen's 1.45 kB bundle - no extra bytes for async state!
| Package | Description | Size |
|---|---|---|
| @sylphx/zen | Core state management | 1.45 kB |
| @sylphx/zen-craft | Immutable updates (powered by Craft) | ~4 kB |
| @sylphx/zen-persistent | localStorage/sessionStorage sync | ~1 kB |
| Package | Framework | Size |
|---|---|---|
| @sylphx/zen-react | React 16.8+ | 216 B |
| @sylphx/zen-preact | Preact 10+ | 177 B |
| @sylphx/zen-vue | Vue 3+ | ~200 B |
| @sylphx/zen-solid | Solid.js | 234 B |
| @sylphx/zen-svelte | Svelte 3-5 | 167 B |
| Package | Description |
|---|---|
| @sylphx/zen-router | Framework-agnostic router |
| @sylphx/zen-router-react | React integration |
| @sylphx/zen-router-preact | Preact integration |
Zen has excellent TypeScript support with full type inference:
import { zen, computed, map, set } from '@sylphx/zen';
const count = zen(0); // Inferred as Zen<number>
const user = map({ name: 'Alice', age: 30 }); // Inferred as Map<{name: string, age: number}>
const doubled = computed([count], (n) => n * 2); // n is inferred as number
// Full type safety
set(count, 'invalid'); // ❌ Type error
set(count, 42); // ✅ OK
setKey(user, 'age', '30'); // ❌ Type error (expects number)
setKey(user, 'age', 30); // ✅ OK
Zen uses a minimal publish-subscribe architecture with advanced optimizations:
All with zero proxy overhead for basic operations and microscopic bundle size.
Zen uses a reactive graph coloring algorithm inspired by Reactively for optimal performance:
This approach eliminates redundant updates in diamond dependencies and enables true lazy evaluation where computed values only update when actually accessed.
# Install dependencies
bun install
# Run tests
bun test
# Run tests in watch mode
bun test:watch
# Run benchmarks
bun run bench
# Type checking
bun run typecheck
# Build all packages
bun run build
If Zen makes your life easier, give it a ⭐ on GitHub!
MIT © Sylph
Built with ❤️ for developers who refuse to compromise on performance or framework lock-in.
Powered by Craft for immutable state updates.
Stop settling for framework lock-in. Choose Zen.
State management that works everywhere, at lightning speed