CursorRules offer a powerful way to communicate your team’s state management patterns to Cursor. When configured correctly, these rules guide the AI to generate code that aligns with your existing architecture, whether you use React Context, Redux Toolkit, Vue’s Composition API, or Zustand. This guide shows you how to write effective CursorRules that capture your team’s specific patterns.
Why State Management Patterns Matter in CursorRules
Every team develops unique approaches to handling application state. Some prefer centralized stores with Redux Toolkit, others favor distributed patterns with React hooks, and some use Zustand for its simplicity. When Cursor generates new components or modifies existing code, it needs to understand these patterns to produce consistent results.
CursorRules act as a persistent instruction set that Cursor references when working on your codebase. Unlike general-purpose prompts, team-specific rules encode conventions that make your codebase cohesive. The key is specificity—vague instructions produce generic code, while detailed patterns produce code that feels like it was written by a team member.
Writing Effective State Management CursorRules
Effective CursorRules follow a structured approach: define the pattern, show concrete examples, and specify any constraints. Here’s a framework you can adapt:
# State Management Patterns
## Our Redux Toolkit Setup
- We use Redux Toolkit with createSlice for all global state
- Slices live in /src/store/slices/
- Each slice includes: name, initialState, reducers, and async thunks
- Selectors are created with createSelector and stored in /src/store/selectors/
## Component State Patterns
- Local state uses useState with explicit type annotations
- useState is preferred over useReducer unless complex state transitions exist
- Form state uses controlled components with onChange handlers
## State Access in Components
- Always import selectors from /src/store/selectors/
- Use useSelector and useDispatch hooks from react-redux
- Never access store state directly—always use selectors
This structure gives Cursor clear guidance on where state lives, how it’s organized, and how components should interact with it.
Pattern Examples for Different Frameworks
React Context Pattern
If your team uses React Context for state management, include specific guidance about Context providers and custom hooks:
## React Context Patterns
- Global UI state lives in /src/context/
- Each context has a Provider component and useContext hook
- Custom hooks wrap useContext with proper TypeScript types
- Context values are memoized with useMemo to prevent unnecessary re-renders
Example context structure:
/src/context/
ThemeContext.tsx # Theme provider and useTheme hook
AuthContext.tsx # Auth provider and useAuth hook
NotificationContext.tsx # Toast notifications
Zustand Pattern
Zustand offers a simpler alternative to Redux. Your CursorRules should reflect its minimal approach:
## Zustand Store Pattern
- All stores use create from zustand
- Stores include TypeScript interfaces for state and actions
- Slices pattern not required—single store per domain
- Actions are defined as functions within the store
Example store:
/src/stores/
useUserStore.ts # User authentication state
useCartStore.ts # Shopping cart state
useUIStore.ts # UI visibility and modals
Redux Toolkit with createAsyncThunk
For teams using Redux Toolkit with async operations, specify how to handle API calls:
## Async State with Redux Toolkit
- Use createAsyncThunk for all API calls
- Handle loading, success, and failure states in extraReducers
- Use useQuery from RTK Query for server-state when possible
- Normalize API responses using createEntityAdapter for large lists
Integrating Rules with Project Structure
CursorRules work best when they reference your actual directory structure. Include a section that maps patterns to file locations:
## File Organization
State-related files follow these locations:
| Pattern Type | Directory |
|-------------|-----------|
| Redux slices | /src/store/slices/ |
| Redux selectors | /src/store/selectors/ |
| React Context | /src/context/ |
| Zustand stores | /src/stores/ |
| API services | /src/services/ |
| Custom hooks | /src/hooks/ |
When creating new state, check if a pattern already exists in these directories.
This mapping helps Cursor place new files in the correct locations and understand relationships between different state management approaches.
Testing State Management Code
Include guidance on how your team tests state logic:
## Testing State Management
- Redux slices: test reducers in isolation with jest
- Custom hooks: test with @testing-library/react-hooks
- Integration: test connected components with mocked store
- Async thunks: use redux-saga-test-plan or waitFor from @testing-library
Common Mistakes to Avoid
When writing CursorRules for state management, avoid these pitfalls:
-
Being too generic: “Use state management” tells Cursor nothing. Instead, specify “Use Redux Toolkit with createSlice for global state.”
-
Missing examples: Abstract descriptions confuse AI models. Show actual code patterns from your codebase.
-
Ignoring TypeScript: If your project uses TypeScript (and it should), include type definitions in your rules.
-
No constraints: Specify what NOT to do. “Don’t use useState for global data” prevents common mistakes.
Updating Rules as Patterns Evolve
Your state management approach will evolve. Set up a process to keep CursorRules current:
-
Review rules during code reviews when state patterns change
-
Add new patterns when introducing libraries or approaches
-
Remove deprecated patterns that your team no longer uses
-
Test new developers’ code generation against rules
Advanced State Patterns: Persistence and Sync
Beyond basic state management, include patterns for persistence and client-server sync. These are frequent sources of inconsistency:
## Persistence Patterns
### LocalStorage and SessionStorage
- Critical data (auth tokens, user preferences) uses localStorage with encryption
- Session state uses sessionStorage only—cleared on tab close
- Implement debounced writes to avoid excessive re-renders
- Validate localStorage data on app load; reset if schema mismatches
### IndexedDB for Complex Data
- Large datasets (>1MB) use IndexedDB with proper indexes
- Maintain a version number for schema migrations
- Use promises or async/await consistently
This prevents developers from accidentally storing sensitive data in plain localStorage or querying unindexed databases.
State Boundaries and Lifting Rules
Help Cursor understand when to lift state up the component tree:
## When to Lift State
State should be lifted to a common ancestor when:
- Multiple components need the same data
- A sibling component depends on another sibling's state changes
- Parent components need to coordinate multiple children
Example: If both Header and SidebarMenu need current user data,
lift the user state to a shared context or Redux store rather than
fetching separately in each component.
This guidance prevents the common mistake of duplicating data in separate useState hooks.
Error Handling Within State
Add specific guidance on managing error states:
## Error State Patterns
- Error states live alongside data states (loading, error, success)
- Use discriminated unions: {status: 'error', error: {...}} vs {status: 'success', data: {...}}
- Never throw errors in reducers—catch and log in thunks
- Clear errors when retrying—don't persist old errors
- Distinguish network errors from validation errors in state structure
This prevents state becoming inconsistent when errors occur.
Real Example: Complete State Management Rule Set
Here’s a comprehensive CursorRule combining multiple patterns:
# State Management Architecture
## Redux Toolkit with RTK Query
### Directory Structure
- /src/store/slices/ - Redux Toolkit slices
- /src/store/selectors/ - Memoized selectors using createSelector
- /src/hooks/useAppDispatch.ts - Typed dispatch hook
- /src/hooks/useAppSelector.ts - Typed selector hook
- /src/api/ - RTK Query definitions
### RTK Query Rules
- All server state uses RTK Query, not manual Redux
- Invalidate tags on mutations to auto-refetch related queries
- Use skip: true for conditional queries instead of calling hooks conditionally
- Define tags carefully: "Posts List" for collections, "Post" with ID for individual items
### Reducer and Action Rules
- Reducers handle state shape changes only
- Reducers do NOT contain side effects or external calls
- Complex logic lives in createAsyncThunk, not reducers
- Use Immer syntax: state.items[0].completed = true (mutate-like syntax)
### Selector Rules
- Always use createSelector for computed state
- Selectors prevent unnecessary re-renders via memoization
- Create separate selectors for each piece of state
- Selectors receive entire state, return specific subset
### Example Pattern
function MyComponent() {
const dispatch = useAppDispatch();
const items = useAppSelector(selectAllItems);
const loading = useAppSelector(selectItemsLoading);
useEffect(() => {
if (items.length === 0 && !loading) {
dispatch(fetchItems());
}
}, [dispatch, items, loading]);
}
With this comprehensive rule set, Cursor generates code that feels consistent with established patterns.
Testing State-Generated Code
Include testing expectations in CursorRules:
## Testing State Code
- Redux slices: Unit test reducers with specific state transitions
- Selectors: Verify they return expected values and filter correctly
- Async thunks: Mock APIs and test pending/fulfilled/rejected states
- Connected components: Use Redux MockStore to verify dispatched actions
- RTK Query: Use setupServer (MSW) to mock API responses
This ensures Cursor generates testable state code when you ask for it.
Related Articles
- Create CursorRules That Enforce Your Team’s Git Commit
- How to Create .cursorrules That Enforce Your Teams React
- Best Practices for Versioning CursorRules Files Across Team
- Writing Custom Instructions That Make AI Follow Your Team’s
- How to Use AI to Help Devrel Teams Create Video Tutorial Scr
Built by theluckystrike — More at zovo.one