Skip to main content
RapidDev - Software Development Agency
cursor-tutorial

How to Generate Redux Toolkit Code with Cursor

Cursor can generate Redux Toolkit code but often produces verbose, untyped slices with redundant boilerplate. By adding .cursor/rules/ that specify RTK conventions with createSlice, createAsyncThunk, and TypeScript generics, referencing your existing store configuration with @file, and providing typed patterns for Cursor to follow, you get clean, fully typed Redux slices with minimal code.

What you'll learn

  • How to configure Cursor rules for Redux Toolkit patterns
  • How to generate typed createSlice with createAsyncThunk
  • How to reference your store setup so Cursor maintains type consistency
  • How to use Cmd+I to generate complete feature slices
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Beginner7 min read10-15 minCursor Free+, React/TypeScript with Redux ToolkitMarch 2026RapidDev Engineering Team
TL;DR

Cursor can generate Redux Toolkit code but often produces verbose, untyped slices with redundant boilerplate. By adding .cursor/rules/ that specify RTK conventions with createSlice, createAsyncThunk, and TypeScript generics, referencing your existing store configuration with @file, and providing typed patterns for Cursor to follow, you get clean, fully typed Redux slices with minimal code.

Generating Redux Toolkit code with Cursor

Redux Toolkit simplifies Redux with createSlice, createAsyncThunk, and built-in Immer. However, Cursor sometimes generates older Redux patterns with manual action creators, switch statements, and untyped state. This tutorial configures Cursor to generate modern RTK code with full TypeScript support.

Prerequisites

  • Cursor installed with a React/TypeScript project
  • @reduxjs/toolkit and react-redux installed
  • A Redux store already configured
  • Basic understanding of Redux Toolkit

Step-by-step guide

1

Create a Redux Toolkit rule for Cursor

Add a project rule that specifies RTK patterns and bans legacy Redux patterns. Include your typed hooks and store configuration so Cursor uses them correctly.

.cursor/rules/redux-toolkit.mdc
1---
2description: Redux Toolkit conventions
3globs: "*slice.ts,*store.ts,*thunk.ts"
4alwaysApply: true
5---
6
7# Redux Toolkit Rules
8- ALWAYS use createSlice for reducer logic (never switch statements)
9- ALWAYS use createAsyncThunk for async operations
10- ALWAYS use PayloadAction<T> for typed action payloads
11- ALWAYS use typed hooks: useAppSelector, useAppDispatch from @/store/hooks
12- NEVER use useSelector or useDispatch directly (no type inference)
13- NEVER use connect() HOC (use hooks instead)
14- NEVER use manual action creators (createSlice generates them)
15- Use EntityAdapter for normalized collections
16- Use RTK Query for data fetching when possible
17
18## File pattern: src/features/{name}/{name}Slice.ts
19## State type exported as {Name}State
20## Selector functions exported as select{Property}

Expected result: Cursor generates modern RTK code with createSlice, typed hooks, and no legacy patterns.

2

Generate a complete feature slice with async thunks

Reference your store hooks and an existing slice as a pattern. Ask for a complete feature slice including state, reducers, async thunks, and selectors.

Cmd+L prompt
1@redux-toolkit.mdc @src/store/hooks.ts @src/features/auth/authSlice.ts
2
3Create a complete productsSlice following the same patterns as authSlice:
41. State type: ProductsState with items, loading, error, selectedId, filters
52. Async thunks: fetchProducts, fetchProductById, createProduct, updateProduct, deleteProduct
63. Reducers: setFilters, setSelectedId, clearError
74. Selectors: selectAllProducts, selectProductById, selectLoading, selectError
85. Use PayloadAction<T> for all reducer payloads
96. Handle loading/error states in extraReducers for all thunks
10
11Export everything: reducer (default), actions, thunks, selectors.

Pro tip: Reference an existing slice with @file so Cursor matches your exact typing patterns. This is more reliable than describing the patterns in the prompt.

Expected result: Cursor generates a complete typed slice matching your existing patterns with createSlice, createAsyncThunk, and typed selectors.

3

Generate typed store hooks for Cursor to reference

Create typed useAppSelector and useAppDispatch hooks that Cursor should always import instead of the untyped react-redux hooks. This ensures type inference works across all generated components.

src/store/hooks.ts
1import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux';
2import type { RootState, AppDispatch } from './store';
3
4export const useAppDispatch: () => AppDispatch = useDispatch;
5export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;

Expected result: Typed hooks that Cursor imports in generated components for full type inference.

4

Generate a component that consumes the slice

Ask Cursor to generate a React component that uses the typed hooks to interact with the Redux store. Reference both the slice and hooks so Cursor generates proper typed dispatch calls.

Cmd+L prompt
1@redux-toolkit.mdc @src/store/hooks.ts @src/features/products/productsSlice.ts
2
3Create a ProductList component that:
41. Uses useAppSelector to read products, loading, and error state
52. Uses useAppDispatch to dispatch fetchProducts on mount
63. Shows a loading spinner while fetching
74. Shows an error message with retry button on failure
85. Renders a list of products with name, price, and category
96. Dispatches setSelectedId when a product is clicked
10
11Use the typed hooks from @/store/hooks, not raw useSelector/useDispatch.

Expected result: Cursor generates a component using useAppSelector and useAppDispatch with full type inference from the slice.

5

Add RTK Query for data fetching

For new features, RTK Query is often better than createAsyncThunk. Show Cursor how to generate an API slice with typed endpoints.

Cmd+L prompt
1@redux-toolkit.mdc @src/store/store.ts
2
3Create an RTK Query API slice for products:
41. Base URL: /api
52. Endpoints: getProducts (query), getProductById (query), createProduct (mutation), updateProduct (mutation), deleteProduct (mutation)
63. Tag types for cache invalidation: ['Product', 'Products']
74. Generated hooks exported for use in components
85. Proper TypeScript types for all request and response shapes
9
10Add the API reducer and middleware to the store configuration.

Expected result: Cursor generates a typed RTK Query API slice with auto-generated hooks and cache invalidation.

Complete working example

src/features/products/productsSlice.ts
1import { createSlice, createAsyncThunk, PayloadAction } from '@reduxjs/toolkit';
2import type { RootState } from '@/store/store';
3
4interface Product {
5 id: string;
6 name: string;
7 price: number;
8 category: string;
9}
10
11interface ProductFilters {
12 category?: string;
13 minPrice?: number;
14 maxPrice?: number;
15 search?: string;
16}
17
18interface ProductsState {
19 items: Product[];
20 selectedId: string | null;
21 filters: ProductFilters;
22 loading: boolean;
23 error: string | null;
24}
25
26const initialState: ProductsState = {
27 items: [],
28 selectedId: null,
29 filters: {},
30 loading: false,
31 error: null,
32};
33
34export const fetchProducts = createAsyncThunk(
35 'products/fetchAll',
36 async (filters: ProductFilters, { rejectWithValue }) => {
37 try {
38 const params = new URLSearchParams(filters as Record<string, string>);
39 const response = await fetch(`/api/products?${params}`);
40 if (!response.ok) throw new Error('Failed to fetch products');
41 return (await response.json()) as Product[];
42 } catch (err) {
43 return rejectWithValue((err as Error).message);
44 }
45 }
46);
47
48const productsSlice = createSlice({
49 name: 'products',
50 initialState,
51 reducers: {
52 setFilters: (state, action: PayloadAction<ProductFilters>) => {
53 state.filters = action.payload;
54 },
55 setSelectedId: (state, action: PayloadAction<string | null>) => {
56 state.selectedId = action.payload;
57 },
58 clearError: (state) => {
59 state.error = null;
60 },
61 },
62 extraReducers: (builder) => {
63 builder
64 .addCase(fetchProducts.pending, (state) => {
65 state.loading = true;
66 state.error = null;
67 })
68 .addCase(fetchProducts.fulfilled, (state, action) => {
69 state.loading = false;
70 state.items = action.payload;
71 })
72 .addCase(fetchProducts.rejected, (state, action) => {
73 state.loading = false;
74 state.error = action.payload as string;
75 });
76 },
77});
78
79export const { setFilters, setSelectedId, clearError } = productsSlice.actions;
80
81export const selectAllProducts = (state: RootState) => state.products.items;
82export const selectLoading = (state: RootState) => state.products.loading;
83export const selectError = (state: RootState) => state.products.error;
84
85export default productsSlice.reducer;

Common mistakes when generating Redux Toolkit Code with Cursor

Why it's a problem: Cursor generates useSelector instead of useAppSelector

How to avoid: Create typed hooks in src/store/hooks.ts and add a rule: ALWAYS use useAppSelector and useAppDispatch from @/store/hooks.

Why it's a problem: Cursor generates switch-case reducers instead of createSlice

How to avoid: Add ALWAYS use createSlice and NEVER use switch statements for reducers to your rules.

Why it's a problem: Missing error handling in createAsyncThunk

How to avoid: Include error handling patterns in your rules with rejectWithValue for all async thunks.

Best practices

  • Create typed hooks (useAppSelector, useAppDispatch) and reference them in rules
  • Use createSlice for all reducer logic with PayloadAction<T> for typed payloads
  • Use createAsyncThunk with rejectWithValue for proper error handling
  • Reference an existing slice with @file when generating new features
  • Export selectors alongside the slice for colocation
  • Consider RTK Query for data fetching instead of manual async thunks
  • Keep slice files under 150 lines by extracting complex thunks to separate files

Still stuck?

Copy one of these prompts to get a personalized, step-by-step explanation.

ChatGPT Prompt

Generate a Redux Toolkit slice for a shopping cart feature with TypeScript. Include state for items, totals, and loading. Use createSlice, createAsyncThunk with rejectWithValue, PayloadAction types, and typed selectors. Follow RTK best practices.

Cursor Prompt

@redux-toolkit.mdc @src/store/hooks.ts @src/features/auth/authSlice.ts Create a notificationsSlice following the same patterns as authSlice. Include state for notifications array, unread count, and loading. Add async thunks for fetch, markRead, and dismiss. Export typed selectors.

Frequently asked questions

Should I use RTK Query or createAsyncThunk?

RTK Query for standard CRUD data fetching. createAsyncThunk for complex async logic with side effects like multi-step workflows, file uploads, or operations that update multiple slices.

How do I handle normalized state with Cursor?

Ask Cursor to use createEntityAdapter from RTK. Reference the adapter documentation in your rules and provide an example of the entity adapter pattern.

Can Cursor generate RTK Query code?

Yes. Reference your store configuration and ask for an API slice with createApi and fetchBaseQuery. Cursor generates typed endpoints with auto-generated hooks.

What about Zustand or Jotai instead of Redux?

If your app does not need Redux's middleware, devtools, or time-travel debugging, Zustand is simpler. Create separate rules for your chosen state management library.

How do I test Cursor-generated slices?

Ask Cursor to generate tests that dispatch actions and verify state changes. RTK slices are pure functions, making them easy to test without mocking.

Can RapidDev help with state management architecture?

Yes. RapidDev evaluates state management needs and implements the right solution, whether Redux Toolkit, Zustand, or React Context, with Cursor rules for ongoing consistency.

RapidDev

Talk to an Expert

Our team has built 600+ apps. Get personalized help with your project.

Book a free consultation

Need help with your project?

Our experts have built 600+ apps and can accelerate your development. Book a free consultation — no strings attached.

Book a free consultation

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.