This skill should be used when the user asks to "create a Zustand store", "add a store slice", "add a persist store", "scaffold state management", or "add Zustand state with selectors".
Create a Zustand store (feature-local or shared) with typed state, actions, selectors, and optional persist middleware.
storeName (required): camelCase hook name (e.g., useAuthStore, usePayInvoiceStore)stateFields (required): array of {name, type, defaultValue} (e.g., {name: "token", type: "string | null", defaultValue: "null"})actions (required): array of action names (e.g., setToken, clearAuth)persist (optional): {key: string, storage: 'localStorage' | 'sessionStorage'} — omit to skip persist middlewareCreates inside the slice's model/ directory:
store.ts — Zustand store with full TypeScript typesselectors.ts — derived selector functions (e.g., selectIsAuthenticated)zustand installed in apps/frontendstore.ts — with persist middleware if persist input provided:import { create } from 'zustand';
import { persist, createJSONStorage } from 'zustand/middleware';
type State = {
// TODO: add fields from stateFields input
// action signatures
};
// With persist:
export const <storeName> = create<State>()(
persist(
(set) => ({
// TODO: default values from stateFields[*].defaultValue
// TODO: action implementations
}),
{
name: '<persist.key>',
// Use persist.storage to select the storage engine:
storage: createJSONStorage(() => localStorage), // replace with sessionStorage if persist.storage === 'sessionStorage'
}
)
);
// Without persist (use when persist input is omitted):
// export const <storeName> = create<State>()((set) => ({
// // TODO: default values and action implementations
// }));
If persist is omitted, use the bare create<State>()((set) => ({ ... })) pattern (no middleware wrapper)
Create selectors.ts with pure functions operating on the store state. Type the state parameter using the State type exported from store.ts:
// Import the State type from the store file
import type { State } from './store';
// Or re-export State from store.ts: export type { State };
// Example selector — replace with fields from stateFields input
export const selectIsAuthenticated = (state: State): boolean =>
state.token !== null;
index.ts:export { <storeName> } from './model/store';
export { selectIsAuthenticated } from './model/selectors';
pnpm -C apps/frontend typecheckE_PERSIST_KEY_REQUIRED: persist.key missing → Zustand requires a unique storage key; pass { name: 'unique-key' } to the persist optionsE_TYPECHECK_UNAVAILABLE: typecheck script missing → run pnpm -C apps/frontend tsc --noEmit directlySee docs/project-overview.md → "FE-03 — Zustand store slice" and the usePayInvoiceStore template.