Documentation
Docs
Introduction
Getting Started
Tutorial: build an app
Core Concepts
Routing
Server-Side Rendering
Mimir, state management
Pages & Layouts
API Routes
Styling & Theming
Building & Deploying
API Reference
Guides
Recipes
FAQ (use cases)
Atoms
An atom is the unit of state in Mimir. It is a small, frozen definition, a unique key, a default
value, and a persistence flag, created with atom(config). It holds no value of its own; the store holds
the live value, keyed by the atom's key.
Defining an atom
atom() validates and freezes the definition:
keymust be a non-empty string. It is the identity of the state, used for storage, hydration, and
subscriptions.
defaultis required (passing nodefaultthrows). It is the value before anything sets the atom.persistdefaults totrue. When a session is active,persist: trueatoms are saved to IndexedDB and
restored on reload; persist: false atoms stay in memory only. (Without a session, persist has no
effect, see Persistence & sessions.)
The returned object is frozen, you cannot mutate a definition. You change the value through the store
(set, hooks), never the atom.
Keys are identity, choose them carefully
The key is how the value is stored, hydrated, and persisted. Two consequences:
- Keys must be globally unique. Two atoms with the same key are the same slot in the store. Namespacing
helps: "cart:items", "ui:sidebar-open", "auth:user".
- Keys are stable contracts. Renaming a key orphans any persisted value under the old name and any
server-seeded value addressed by the old name. Treat a key like a database column name.
Where atoms live
By convention, in atoms/, one module per concern. Import them where used:
No <Provider> wraps your app, atoms are module-level singletons backed by the single store. Importing the
atom is all the "wiring" there is.
Default values and laziness
The store is lazy: an atom's value is materialised the first time it is read or written (_ensureAtom).
Until then it logically holds its default. This means defining a thousand atoms costs nothing until they
are touched.
default can be any serializable value, primitive, array, or object:
Keep
defaultserializable (no functions, class instances,Map/Set, circular refs). Mimir serializes atom values for SSR seeding and IndexedDB persistence; non-serializable defaults break those paths. See Pitfalls.
Typing atoms
atom<T>(config) infers T from default, or you can specify it for unions and nullable values:
useAtom(themeAtom) is then typed [Theme, (v: Theme | ((p: Theme) => Theme)) => void].
Atoms vs selectors
An atom is writable state. A selector is read-only derived state computed from other atoms (or
selectors). You set atoms; you only get/read selectors. See Selectors.
Next: reading and writing atom values, Reading & writing.