← All @molecule/* packages · App templates

@molecule/app-state-zustand

Provider bond · state · App (browser) · v1.0.1 · Apache-2.0

Zustand state provider for molecule.dev

npm install @molecule/app-state-zustand

npm · Source on GitHub · Implements @molecule/app-state

How it works

@molecule/app-state-zustand is a provider bond on the app (browser) side: it implements the state core interface (@molecule/app-state) with a concrete vendor or library behind it.

Your code calls the core; you wire this provider once at startup. Swapping vendors later is one line in that wiring, not a rewrite.

import { setProvider } from '@molecule/app-state'
import { createStore, provider } from '@molecule/app-state-zustand'

setProvider(provider)

// persist is a zustand-bond EXTENSION: the core createStore() accepts only the
// portable StoreConfig — create persisted stores via the bond's own createStore.
const store = createStore({
  initialState: { theme: 'light', draft: '' },
  persist: { name: 'app-settings', partialize: (s) => ({ theme: s.theme }) },
})

Works with: @molecule/app-state

Reference

Auto-generated, AI-first package reference for the molecule.dev ecosystem. It is written to be read by coding agents as much as by people, and is generated from this package's source — edit src/index.ts JSDoc, not this file.

Zustand state provider for molecule.dev.

Implements the StateProvider interface from @molecule/app-state on zustand/vanilla (with subscribeWithSelector), with optional per-store persistence and slice helpers for direct-Zustand usage.

Quick Start

import { setProvider } from '@molecule/app-state'
import { createStore, provider } from '@molecule/app-state-zustand'

setProvider(provider)

// persist is a zustand-bond EXTENSION: the core createStore() accepts only the
// portable StoreConfig — create persisted stores via the bond's own createStore.
const store = createStore({
  initialState: { theme: 'light', draft: '' },
  persist: { name: 'app-settings', partialize: (s) => ({ theme: s.theme }) },
})

Type

provider

Installation

npm install @molecule/app-state-zustand @molecule/app-state zustand

API

Interfaces

Slice

A Zustand store slice: a named partition of state with its initial values and action creators.

interface Slice<T extends object, A extends object> {
  name: string
  initialState: T
  actions: (set: SetState<T>, get: GetState<T>) => A
}

SliceConfig

Configuration for a Zustand store slice (name, initial state, and action creators).

interface SliceConfig<T extends object, A extends object> {
  name: string
  initialState: T
  actions: (set: SetState<T>, get: GetState<T>) => A
}

StateProvider

State provider interface that all state management bond packages must implement. Provides the store creation factory.

interface StateProvider {
  /**
   * Creates a new store.
   */
  createStore<T>(config: StoreConfig<T>): Store<T>
}

Store

Reactive state container with getState, setState, subscribe, and destroy.

All state management providers must implement this interface.

interface Store<T> {
  /**
   * Gets the current state.
   */
  getState(): T
  /**
   * Sets the state (partial or via updater function).
   */
  setState(partial: Partial<T> | ((state: T) => Partial<T>)): void
  /**
   * Subscribes to state changes.
   * Returns an unsubscribe function.
   */
  subscribe(listener: StateListener<T>): () => void
  /**
   * Destroys the store and cleans up subscriptions.
   */
  destroy(): void
}

StoreConfig

Configuration for creating a store (initial state, optional name, and middleware chain).

interface StoreConfig<T> {
  /**
   * Initial state value.
   */
  initialState: T
  /**
   * Optional name for debugging.
   */
  name?: string
  /**
   * Optional middleware functions.
   */
  middleware?: StoreMiddleware<T>[]
}

StoreWithActionsConfig

Store with actions configuration.

interface StoreWithActionsConfig<T extends object, A extends object> {
  initialState: T
  actions: (set: SetState<T>, get: GetState<T>) => A
  name?: string
  middleware?: StoreMiddleware<T>[]
  devtools?: boolean
  persist?: ZustandStoreConfig<T>['persist']
}

ZustandStoreConfig

Extended store config for Zustand-specific options.

interface ZustandStoreConfig<T> extends StoreConfig<T> {
  /**
   * Enable devtools integration.
   */
  devtools?: boolean

  /**
   * Persist options.
   */
  persist?: {
    /**
     * Storage key.
     */
    name: string

    /**
     * Storage to use (defaults to localStorage).
     */
    storage?: Storage

    /**
     * Partialize the state to persist.
     */
    partialize?: (state: T) => Partial<T>
  }
}

Types

GetState

Get state function type.

type GetState<T> = () => T

SetState

Function to update store state with a partial object or updater function.

type SetState<T> = (partial: Partial<T> | ((state: T) => Partial<T>)) => void

StateListener

Callback invoked whenever store state changes.

type StateListener<T> = (state: T, prevState: T) => void

StoreMiddleware

Store middleware function. Wraps the set function to intercept state updates (e.g. for logging, persistence, or devtools).

type StoreMiddleware<T> = (set: SetState<T>, get: GetState<T>) => SetState<T>

Functions

combineSlices(slices)

Combines multiple slices into a single Zustand store. Each slice's state is nested under its name key, and each slice's actions are exposed as top-level methods on the store.

function combineSlices(slices: S): Store<Record<string, unknown>>
  • slices — Array of slices created by createSlice.

Returns: A molecule Store with combined state and all slice actions merged onto it.

createProvider()

Creates a Zustand state provider for use with setProvider() from @molecule/app-state.

function createProvider(): StateProvider

Returns: A StateProvider that creates Zustand-backed stores.

createSelector(selector, equalityFn)

Creates a memoized selector that only recomputes when the selected value changes (determined by the equality function, defaulting to Object.is).

function createSelector(
  selector: (state: T) => R,
  equalityFn?: (a: R, b: R) => boolean,
): (state: T) => R
  • selector — Function that extracts a derived value from state.
  • equalityFn — Equality comparator for the derived value; defaults to Object.is.

Returns: A memoized selector function that returns the cached result when the derived value is equal.

createSlice(config)

Creates a named slice of state for use with combineSlices. A slice defines a name, initialState, and an actions factory that receives scoped set/get functions.

function createSlice(config: SliceConfig<T, A>): Slice<T, A>
  • config — Slice configuration with name, initialState, and actions factory.

Returns: A Slice object (the config itself, used as a descriptor by combineSlices).

createStore(config)

Creates a Zustand-backed store that conforms to the molecule Store interface. Uses zustand/vanilla with subscribeWithSelector middleware. Supports molecule middleware, and optional persistence to localStorage (or a custom storage backend).

function createStore(config: ZustandStoreConfig<T>): Store<T>
  • config — Store configuration including initialState, optional molecule middleware, and optional persist config with name, storage, and partialize.

Returns: A molecule Store with getState, setState, subscribe, and destroy.

createStoreWithActions(config)

Creates a store with actions (Zustand pattern).

function createStoreWithActions(config: StoreWithActionsConfig<T, A>): Store<T> & A
  • config — Configuration with initialState and an actions factory (set, get) => actionMap.

Returns: A molecule Store merged with the action functions, so actions can be called directly on the store.

Constants

provider

Default Zustand state provider instance.

const provider: StateProvider

Core Interface

Implements @molecule/app-state interface.

Bond Wiring

Setup function to register this provider with the core interface:

import { setProvider } from '@molecule/app-state'
import { provider } from '@molecule/app-state-zustand'

export function setupStateZustand(): void {
  setProvider(provider)
}

Injection Notes

Requirements

Peer dependencies:

  • @molecule/app-state ^1.0.1

Runtime Dependencies

  • @molecule/app-state

  • zustand

  • Persistence is best-effort and silent. persist defaults to raw localStorage (no-ops server-side); read/write failures (quota, private browsing, serialization) are swallowed by design — the in-memory store keeps working, but nothing sticks. Pass persist.storage to use another backend and partialize to bound what is written.

  • Persisted state is shallow-merged over initialState on creation — old keys survive shape changes; version/namespace the persist.name when the shape breaks.

  • destroy() is a no-op (Zustand v5 has no store destroy) — drop references and call the unsubscribe functions returned by subscribe().

  • setState shallow-merges partials/updater results (molecule Store semantics).

  • createStoreWithActions/createSlice/combineSlices are direct-Zustand helpers — stores built with them bypass the molecule Store contract.