Introduction
Stunk - A lightweight, framework-agnostic state management library built on atomic chunk principles.
Stunk is a lightweight, reactive state management library built on atomic principles. Instead of one giant global store, you break state into small, independent pieces called chunks — each one self-contained, reactive, and composable.
No reducers. No boilerplate. No magic. Just state.
import { chunk } from "stunk";
const count = chunk(0);
count.get(); // 0
count.set(1); // set directly
count.set((n) => n + 1); // or derive from previous
count.reset(); // back to 0Stunk is framework-agnostic at its core. React, Vue, Svelte, Solid, or vanilla
JS — it works everywhere. Official React integration ships with the package
via stunk/react.
How it works
Every piece of state in Stunk is a chunk — a tiny reactive container that holds a single value. Chunks can be read, updated, subscribed to, derived from, and composed together.
import { chunk, computed } from "stunk";
const price = chunk(100);
const quantity = chunk(3);
// Derived from a single chunk
const discounted = price.derive((p) => p * 0.9);
// Computed from multiple chunks
const total = computed([price, quantity], (p, q) => p * q);
total.get(); // 300 — updates automatically when price or quantity changesThink of chunks as the atoms of your application state. Small, focused, and composable.
Key Features
Atomic State
Break state into independent chunks. No global store, no coupling.
Fine-Grained Reactivity
Only the components that depend on a chunk re-render when it changes.
Derive & Computed
Derive state from one chunk or compose across multiple with full reactivity.
Async Support
Built-in loading, error, and data states for async operations.
Middleware
Extend chunks with logging, persistence, validation and more.
Time Travel
Undo and redo state changes with built-in history management.
React in 30 seconds
If you're using React, the stunk/react integration gives you hooks that are reactive out of the box:
import { chunk } from "stunk";
import { useChunk } from "stunk/react";
const counter = chunk(0);
function Counter() {
const [count, setCount] = useChunk(counter);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount((n) => n + 1)}>Increment</button>
</div>
);
}The component re-renders only when counter changes — nothing else.
Installation
npm install stunkpnpm add stunkyarn add stunkbun add stunk