
Security News
Socket Releases Free Certified Patches for Nuxt Security Vulnerabilities
Socket releases free Certified Patches for high-severity Nuxt vulnerabilities, including server-side remote code execution through server island props.
@mongez/atom
Advanced tools
An agnostic state management tool that work with any framework on browser or server
A framework-agnostic, action-shaped state primitive with first-class SSR isolation, derived values, persistence, and Redux DevTools.
@mongez/atom is the core of the Mongez state-management family. The React adapter lives in @mongez/react-atom; the client-side server-state cache in @mongez/atomic-query.
The atom isn't just a value — it's a value with methods bound to it. Instead of writing setters and helper functions everywhere, you define actions on the atom itself and call them as verbs: cart.push(item), modal.open(), auth.login(creds).
yarn add @mongez/atom
# peer deps: @mongez/events, @mongez/reinforcements
import { createAtom, atomCollection, derive } from "@mongez/atom";
// 1. A boolean toggle with action verbs.
const sidebar = createAtom({
key: "ui.sidebar",
default: false,
actions: {
open() { this.update(true); },
close() { this.update(false); },
toggle() { this.update(!this.value); },
},
});
sidebar.toggle();
// 2. A list with built-in mutation helpers.
type Todo = { id: number; text: string; done: boolean };
const todos = atomCollection<Todo>({ key: "todos", default: [] });
todos.push({ id: 1, text: "Buy bread", done: false });
todos.remove(t => t.done);
// 3. A derived atom — auto-tracks its dependencies.
const incompleteCount = derive("todos.incomplete", get =>
get(todos).filter(t => !t.done).length,
);
incompleteCount.value; // 1
todos.push({ id: 2, text: "Read book", done: false });
incompleteCount.value; // 2 (recomputes automatically)
| Export | Purpose |
|---|---|
createAtom | The atom factory. |
atomCollection | Array-shaped atoms with mutation verbs. |
derive | Computed atoms with auto-tracked dependencies. |
AtomStore / createAtomStore | Per-request isolation primitive for SSR. |
enableAtomDevtools | Redux DevTools bridge with time-travel. |
persist (option on AtomOptions) | Persist atom values via localStorage or any adapter. |
getAtom, atomsList, atomsObject | Registry helpers. |
const counter = createAtom({ key: "counter", default: 0 });
// Reads
counter.value;
counter.defaultValue;
// Writes
counter.update(5);
counter.update(prev => prev + 1);
counter.silentUpdate(0); // no update event
counter.reset(); // back to default + emit events
counter.silentReset(); // back to default, no update event
// Subscriptions
counter.onChange((next, prev) => …); // returns { unsubscribe }
counter.onReset(…);
counter.onDestroy(…);
// Lifecycle
counter.clone(); // returns a new atom with key `${key}.clone.{n}`
counter.destroy();
For object-valued atoms, you also get:
const user = createAtom({
key: "user",
default: { name: "Anon", age: 0 },
});
user.merge({ age: 31 }); // shallow merge + update event
user.change("name", "Alice"); // set one key + update event
user.silentChange("age", 32); // set one key, no update event
user.get("name"); // read one key
user.watch("name", (next, prev) => …); // subscribe to one key only
Calling change / merge / watch on a primitive atom (Atom<boolean>, Atom<number>, Atom<string>) is a compile error — the methods are stripped from the type because they would silently corrupt the value at runtime.
import { createAtom, derive } from "@mongez/atom";
const firstName = createAtom({ key: "first", default: "Ada" });
const lastName = createAtom({ key: "last", default: "Lovelace" });
const fullName = derive("fullName", get => `${get(firstName)} ${get(lastName)}`);
fullName.value; // "Ada Lovelace"
firstName.update("Grace");
fullName.value; // "Grace Lovelace"
Conditional reads work — branches re-track dependencies on each run:
const branch = createAtom({ key: "branch", default: "first" as "first" | "last" });
const selected = derive("selected", get =>
get(branch) === "first" ? get(firstName) : get(lastName),
);
Chained derivations propagate: a derive that reads another derive recomputes when either changes.
import { createAtom, type PersistAdapter } from "@mongez/atom";
// Built-in localStorage adapter (client-only; no-ops on the server)
const themeAtom = createAtom({
key: "theme",
default: "light",
persist: true,
});
// Or plug in any adapter (sync or async)
const myAdapter: PersistAdapter = {
get: (key) => myCache.get(key),
set: (key, value) => myCache.set(key, value),
remove: (key) => myCache.delete(key),
};
const userAtom = createAtom({
key: "user",
default: { name: "Anon" },
persist: myAdapter,
});
Behavior:
silentUpdate (no update event fires for the hydration).update writes through to the adapter.reset() removes the entry.For SSR, pair with a cookie-aware adapter so the server can read the persisted value during render — localStorage doesn't exist on the server and the built-in adapter no-ops there.
AtomStoreThe module-level atoms registry is shared per Node process. Two concurrent SSR requests would write to the same atoms. AtomStore solves it:
import { createAtomStore } from "@mongez/atom";
import { userAtom } from "./state";
const store = createAtomStore();
store.use(userAtom).update({ name: "Alice" });
userAtom.value; // { name: "Anon" } (template untouched)
store.get("user")?.value; // { name: "Alice" } (scoped to this store)
API:
class AtomStore {
use<V, A>(template: Atom<V, A>): Atom<V, A>; // lazy clone
get<V>(key: string): Atom<V> | undefined;
has(key: string): boolean;
list(): Atom<any>[];
hydrate(snapshot: Record<string, unknown>): void;
snapshot(): Record<string, unknown>;
destroy(): void;
}
For the React side (<AtomStoreProvider>, useAtom, useAtomStore, hydration helpers), see @mongez/react-atom.
import { enableAtomDevtools } from "@mongez/atom";
if (process.env.NODE_ENV !== "production") {
enableAtomDevtools({
name: "MyApp",
ignore: [/^mouse\./, /^scroll\./], // skip high-frequency atoms
});
}
Connects to window.__REDUX_DEVTOOLS_EXTENSION__. You get a live atom list, an update timeline, and time-travel via JUMP_TO_STATE. No-op when the extension isn't installed. Tree-shaken when you don't import it.
Each atom emits on the @mongez/events bus under the namespace atoms.${key}:
atoms.${key}.update — fired by update / change / mergeatoms.${key}.reset — fired by reset / silentResetatoms.${key}.delete — fired by destroyNamespace matching in @mongez/events is segment-aware, so destroying users.1 does not also destroy users.10.
type Item = { id: string; price: number; qty: number };
const cart = atomCollection<Item>({
key: "cart",
actions: {
get total() {
return this.value.reduce((sum, i) => sum + i.price * i.qty, 0);
},
setQty(this: Atom<Item[]>, id: string, qty: number) {
this.update(this.value.map(i => (i.id === id ? { ...i, qty } : i)));
},
},
});
cart.push({ id: "a", price: 10, qty: 2 });
cart.total; // 20
cart.setQty("a", 5);
cart.total; // 50
const canCheckout = derive("canCheckout", get =>
get(cart).length > 0 &&
get(userAtom).loggedIn &&
!get(checkoutLoading).isLoading,
);
if (canCheckout.value) { /* show button */ }
const themeAtom = createAtom({
key: "ui.theme",
default: "light",
persist: true,
});
// On next page load, themeAtom.value is whatever the user last set.
Atom<V> is a conditional type. Object-only methods (merge, change, silentChange, get(key), watch(key, cb)) only exist when V is an object/array. Atom<boolean>.change(...) is a compile error.AtomActions<V> no longer collapses to any. Per-action type safety is preserved.AtomOptions.default: V must be a complete value (no Partial<V> default).See MIGRATION.md for the v1 → v2 transition.
| Package | Purpose |
|---|---|
@mongez/react-atom | React hooks, <AtomStoreProvider>, SSR helpers, preset atoms. |
@mongez/atomic-query | Client-side query cache: useQuery, useMutation, useInfiniteQuery, useSuspenseQuery. |
@mongez/events | Tiny event bus. Used internally. |
@mongez/reinforcements | TypeScript utility belt. clone, get, … used internally. |
MIT
FAQs
An agnostic state management tool that work with any framework on browser or server
The npm package @mongez/atom receives a total of 75 weekly downloads. As such, @mongez/atom popularity was classified as not popular.
We found that @mongez/atom demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Socket releases free Certified Patches for high-severity Nuxt vulnerabilities, including server-side remote code execution through server island props.

Security News
An open letter signed by 50 companies, from NVIDIA and Microsoft to Mistral and Hugging Face, urges Washington not to restrict open weight AI.

Security News
/Research
A fake corepack.org site is impersonating the Node.js tool and delivers an infostealer and proxyware to developers who download it.