Home › React › Zustand state management Cursor rules
Zustand state management Cursor rules
Cursor rules for React state with Zustand: small typed stores, selectors, actions in the store, persist and devtools middleware, and testing.
CursorReact
How to use
Save this as .cursor/rules/zustand.mdc in your repository root, commit it, and your agent will pick it up automatically. Edit the commands to match your project.
Note: Review and test before use. Provided as is, without warranty. See Terms.
.cursor/rules/zustand.mdcDownload ---
description: Zustand store conventions
globs: ["src/**/*.{ts,tsx}"]
alwaysApply: false
---
# Zustand
- Use Zustand for client UI state only (filters, panels, drafts, session-local preferences). Server data belongs in TanStack Query/SWR/loaders, not in a store.
- One store per domain in `src/stores/<domain>.ts`, created with `create<State>()((set, get) => ({ ... }))` (note the curried call for TypeScript).
- State and actions live together; components call `useCartStore((s) => s.addItem)`. No `setState` calls scattered across components.
- Always select the smallest slice: `useCartStore((s) => s.items.length)`. When selecting several values, use `useShallow` from `zustand/react/shallow` to avoid re-render loops.
- Never return a new object/array from a selector without `useShallow`; it re-renders every time.
- Update immutably with `set((s) => ({ items: [...s.items, item] }))`, or add the `immer` middleware if the repo already uses it.
- Middleware order: `devtools(persist(immer(...)))` as needed. `persist` needs a unique `name`, a `version` and a `migrate` when the shape changes; use `partialize` to persist only what must survive reloads.
- Derived values: compute in selectors or small helper hooks, not stored copies.
- For Next.js/SSR, create the store per request with `createStore` + a React context provider; a module-level store leaks state between users.
## Tests
Reset the store in `beforeEach` (`useStore.setState(initialState, true)`) and test actions directly.
## Done when
`npx tsc --noEmit`, lint and tests pass.