Skip to main content
Version: 1.3.0

Decision Matrix

Use these tables when the code is "almost obvious" but one wrong persistence choice would change user behavior after reload.

set(null) vs remove() vs reset()

NeedActionResult after reload
Keep an explicit "cleared" stateset(null)Still cleared
Forget the key entirelyremove()Falls back to defaultValue
Restore the default as a stored valuereset()Rehydrates defaultValue

Rule of thumb:

  • Use set(null) for durable clear intent.
  • Use remove() for absence.
  • Use reset() when the default itself should become the new persisted value.

Shopping Cart Semantics

NeedRecommended representation or actionWhy
Active cart with zero itemsCartState with items: []The cart still exists and can accept new lines immediately
Explicit “no cart” or “cart unavailable” stateset(null) on CartState | nullOnly when null has real product meaning
Forget cart after checkout, logout, or recoveryremove()The next read falls back to defaultValue
Restore a seeded default cart shapereset()Re-persists the configured default object
Header badge count or subtotalDerive from cart.itemsPrevents drift between stored lines and stored summaries

Migration vs reconcile(...)

SituationUseWhy
Stored shape changed between explicit versionsSchema migrationStructural compatibility belongs to version transitions
Every write should normalize the valueWrite-time migration (fromVersion === toVersion)Keeps writes canonical
Existing shape is fine, but defaults or policy should refreshreconcile(...)Conditional read-time rewrite without inventing a new version
Invalid or stale data should be discardedRecovery or reset flowSafer than forcing a questionable transform

Should This State Persist?

State shapePersist?Why
Theme, density, durable layout preferenceYesUsers expect it after reload
Saved filters users intentionally restoreYesThis is durable preference state
User-authored draft contentUsually yesLost work is expensive
Hover, focus, drag, loading, optimistic flagsNoRehydrating runtime-only UI feels wrong
Temporary dirtiness and validation errorsNoThese describe a session, not durable intent
Server response cache timestampsUsually noPrefer cache logic over UI persistence
Access tokens, refresh tokens, session secretsNoThese are credentials, not durable UI state
Safe per-user drafts or saved filtersConditionallyScope them to the authenticated user and clear them on auth loss

SSR Mode Choice

NeedConfig
Default SSR behaviorNo SSR config
Deterministic server placeholderssr.serverValue
Delay persisted read until after mountssr.hydration: "client-only"
Make every key inherit delayed hydrationMnemonicProvider ssr={{ hydration: "client-only" }}

Storage Adapter Choice

NeedRecommended path
Standard browser persistenceDefault provider storage (localStorage)
Per-tab persistencestorage={window.sessionStorage}
Custom backend with synchronous facadeProvide a StorageLike wrapper
Cross-tab sync on a custom backendImplement storage.onExternalChange(...)
Direct async reads or writes from the hook contractNot supported in beta 1

Auth Cleanup Choice

NeedRecommended path
Forget auth-scoped private state on logout or expiryClear the authenticated namespace before swap, or use a temporary recovery boundary for the last user namespace
Keep an explicit cleared value for the same authenticated userset(null)
Restore a known default for the same authenticated userreset()
Prevent user A data from appearing for user Buser-aware namespace such as app.user.${userId}
Enforce auth policy when stale data is read backreconcile(...) plus event-based cleanup

See Auth-Aware Persistence for the full logout, expiry, and cross-tab cleanup pattern.