Back to Guides
Framework Combos

Zustand Conventions Your AI Agent Will Actually Follow

Zustand is simple but flexible -which means AI agents make different choices every time. Here's how to encode your store conventions.

Last updated: 2026-07-01

Zustand flexibility = AI inconsistency

Zustand's minimal API means there are many valid ways to structure stores: one global store vs many slices, using immer vs vanilla setters, selectors inline vs extracted. Without rules, AI agents make different architectural choices in different files -one store is sliced, another is flat, some use immer, some don't.

The key decisions to encode

(1) One store per domain or one global store with slices? (2) Direct mutations with immer or functional setters? (3) How to type the store in TypeScript. (4) When to use Zustand at all -vs useState for local state, vs React Query for server state. (5) Selector patterns to prevent unnecessary re-renders.

Zustand rules template

Add this to your .cursor/rules or CLAUDE.md.

.cursor/rules/zustand.mdc
---
description: Zustand state management conventions
globs: ["src/store/**", "**/*.ts", "**/*.tsx"]
alwaysApply: false
---

# Zustand State Management Rules

## When to Use Zustand
✓ Global UI state that is NOT server data: modal open/closed, active tab, user preferences.
✗ Server data (API responses) → use React Query / TanStack Query.
✗ Form state → use react-hook-form.
✗ Local component state → use useState.

## Store Structure
- One store file per domain: src/store/ui-store.ts, src/store/auth-store.ts.
- Export a typed store hook and the store itself.
- TypeScript interface for every store shape:

```typescript
interface UIStore {
  isSidebarOpen: boolean
  activeModal: 'login' | 'signup' | null
  setIsSidebarOpen: (open: boolean) => void
  setActiveModal: (modal: UIStore['activeModal']) => void
  closeAllModals: () => void
}

export const useUIStore = create<UIStore>((set) => ({
  isSidebarOpen: false,
  activeModal: null,
  setIsSidebarOpen: (open) => set({ isSidebarOpen: open }),
  setActiveModal: (modal) => set({ activeModal: modal }),
  closeAllModals: () => set({ activeModal: null }),
}))
```

## Selectors
- Use granular selectors to prevent unnecessary re-renders:
  ✓ const isSidebarOpen = useUIStore((s) => s.isSidebarOpen)
  ✗ const { isSidebarOpen } = useUIStore()  // re-renders on any store change

## Naming
- Store files: src/store/[domain]-store.ts
- Hook exports: useXStore (useUIStore, useAuthStore)
- Boolean state: isX / hasX / canX prefix

Generate state management rules for your project

standarx generates a complete rules file with your state management patterns -Zustand, Context, and React Query boundaries defined.

Generate my rules file