An application state management library to solve the "Single-Timeline State Paradox" by introducing Git-style branching semantics directly into synchronous local memory space.
Leanness by Design — Unlike Redux/Immer-history setups that accumulate memory leaks over long sessions, multiverse automatically destroys patch history the moment a branch is merged or discarded via native Garbage Collection. No commit graphs, no time-travel overhead — just clean, predictable memory.
Deterministic UI Synchronization — Built for the single-threaded React event loop. The Last-Write-Wins (LWW) merge strategy mirrors how async server responses and background workers commit mutations sequentially through deterministic event handlers. No complex 3-way merge UI needed — because in React, mutations are already serialized.
In modern React, Vue, or Vanilla frontend apps, we constantly struggle with Optimistic UI Updates and Modal Drafts. Consider opening a modal to edit a complex data object. You have two choices:
- Deep clone the object into a temporary
draftDatastate, and write custom logic to apply changes back to the main store when the user hits "Save". - Mutate the main store immediately, and write complex logic to reverse mutations if the user hits "Cancel" or if an API call fails.
This is because we live in a Single-Timeline paradigm.
What if your local application state worked like Git branches?
With multiverse-js, you fork your state. You mutate your sandbox timeline exactly like you would mutate the main timeline, with O(K) performance thanks to under-the-hood Proxy lazy-evaluation.
If the API call fails or the user cancels? You simply discard() the branch. The timeline collapses painlessly.
If the API call succeeds? You merge() the branch. The universe patches effortlessly fold your changes into the main timeline, gracefully handling conflicts (even if the main timeline advanced or deleted objects while you were branched).
import { Multiverse } from 'multiverse-js';
const state = new Multiverse({
metrics: { connections: 0 },
users: [{ id: 1, name: 'Alice', role: 'Admin' }],
lastSync: new Date() // Complex instances are preserved natively!
});Open your modal component and just render the isolated branch!
// Create a temporary timeline
state.fork('optimistic-save');
state.mutate(draft => {
// This draft mutation is fully isolated!
// Powered by a lazy Proxy engine, it only clones what you actually touch (Copy-on-Write).
const alice = draft.users.find(u => u.id === 1);
if (alice) alice.name = 'Alice Wonderland';
}, 'optimistic-save');multiverse-js ships with a useMultiverse hook powered by useSyncExternalStore for tear-free concurrent rendering.
import { useMultiverse } from 'multiverse-js/react';
import { state } from './store';
function OptimisticProfile() {
// Subscribe specifically to the 'optimistic-save' branch.
// The component only re-renders when the `users` array changes in this branch.
const users = useMultiverse(state, (s) => s.users, 'optimistic-save');
return <div>{users[0].name}</div>; // Renders "Alice Wonderland"
}React to async API boundaries without writing complex rollback reducers.
try {
await api.saveUser(1, { name: 'Alice Wonderland' });
// It worked! Effortlessly push the patched timeline to reality.
state.merge('optimistic-save');
state.squash(); // Optional: Garbage collect the patch history to free memory
} catch (error) {
// It failed! Throw the sandbox away. No rollbacks required.
state.discard('optimistic-save');
}These demos run locally with tsc + node and do not require React or API keys.
npm run demo:optimistic
npm run demo:merge
npm run demo:agentsIf you want the full pass:
npm run demo:allWhat each demo shows:
demo:optimistic: modal draft workflow with isolated edits, cancel, and save.demo:merge: primitive arrays, entity arrays, and last-merge-wins conflict semantics.demo:agents: async branch orchestration without depending on an external LLM.
Tested on WSL2 Ubuntu, Node.js 22.22.0 — 10,000 element tree, single deep mutation:
| Operation | Throughput | Latency | Complexity |
|---|---|---|---|
| Fork Branch | 2.9M ops/sec | 431 ns | O(1) — pointer copy |
| Single Path Mutation | 65 ops/sec | 15 ms | O(K) — only mutated path |
| Dual Branch + LWW Merge | 50K ops/sec | 22 μs | O(K) — batched patches |
| Atomic Date/Map/Set Replace | ~225K ops/sec | 5–7 μs | O(1) — no Proxy overhead |
Key differentiators:
fork()= pure pointer assignment (3M ops/sec)mutate()= 15ms on 10k tree (no O(N) scan — lineage key tracking)merge()= 50K ops/sec (short-circuit finalizeDraft via mutatedChildren Map)- Date/Map/Set/custom classes = atomic replacement (internal slot protection)
Run locally: npm run bench
There is also a small browser playground in examples/react-demo that uses the shipped useMultiverse hook directly from src/.
npm run demo:react:dev
npm run demo:react:buildIt includes:
- A modal-style draft editor with
fork,merge, anddiscard. - A merge playground for relative array patching and conflict resolution.
- An async orchestration scene that simulates parallel agent branches.
Due to our strict Identity Contract and custom Patch Engine, multiverse-js intelligently applies only the semantic delta.
To guarantee structural safety, objects inside arrays must have an id property. If Branch A is modifying a deeply nested property (e.g., user.profile.age), but Main deleted the user entirely before Branch A could merge, multiverse-js gracefully ignores the orphan patch. It tracks the entity by its id, recognizes it is natively gone, and collapses the mutation. No silent array-index overwriting.
To prevent silent data loss, multiverse-js enforces strict array homogeneity. An array must consist of 100% primitives OR 100% objects with id properties. Mixing primitives and objects in the same array will throw a runtime error during mutation, keeping your data structures predictable.
If two branches both modify config.theme simultaneously, the branch that merges last functionally overwrites the property. This is not a limitation — it mirrors the single-threaded React event loop where async responses arrive sequentially and the last setState wins. No visual conflict resolver needed; the UI thread serializes naturally.
If your array contains primitive values (e.g., ['A', 'B', 'A']), the engine uses a rigorous dynamic programming LCS diffing algorithm. If a branch appends 'C' and the main timeline unshifts 'X', merging results perfectly in ['X', 'A', 'B', 'A', 'C'] without destroying sequence data or getting confused by duplicates.
| We Don't Do | Why | What You Get Instead |
|---|---|---|
| Time-travel / checkout / commit graph | No memory for abandoned history; GC cleans on discard()/merge() |
Leanness by Design — zero memory leaks, predictable O(K) memory |
| 3-way visual merge / CRDT semantic resolution | React event loop is single-threaded; mutations serialize naturally | Deterministic UI Sync — LWW matches React's setState semantics |
| Proxies for Date, Map, Set, custom classes | Internal slots break Proxy traps | Atomic Replacement — safe, predictable replace patches |
| Rebase / concurrent branch divergence | Scope: optimistic UI drafts, not multi-user real-time | Micro-Branching — modal drafts, async agent orchestration |
Use multiverse for: Modal drafts, optimistic UI, async agent pipelines, form isolation. Look elsewhere (Yjs, Automerge, Redux) for: Multi-user collab, full history audit, offline-first sync.
This project is open-source and licensed under the permissive Boost Software License 1.0 (BSL-1.0).
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED. In no event shall the authors or copyright holders be liable for any claim, damages, or other liability, whether in an action of contract, tort, or otherwise, arising from, out of, or in connection with the software or the use or other dealings in the software.
You are free to use it in commercial apps, startups, or personal projects entirely at your own risk.
If multiverse helps you manage complex UI branching state or simplifies your architecture, consider buying me a coffee or sponsoring development via GitHub Sponsors! Your support helps keep the project maintained and feature-rich.