The official, opinionated, batteries-included toolset for efficient Redux development
Redux Toolkit is the official, opinionated toolset for writing Redux applications with significantly less boilerplate code. Created by the Redux team to address longstanding developer complaints about Redux complexity, it provides a standardized approach to Redux development with sensible defaults and built-in best practices. The package includes essential utilities like configureStore(), createSlice(), and createAsyncThunk() that handle common patterns automatically, while also bundling frequently-used middleware like Redux Thunk and utilities like Reselect.
The package emerged from years of feedback showing developers found Redux store configuration overly complex, required too many additional packages for practical use, and demanded excessive manual code for actions and reducers. Redux Toolkit doesn't replace Redux—it wraps and enhances it with better ergonomics while maintaining full compatibility with the Redux ecosystem. You can adopt it incrementally in existing Redux applications or use it as the foundation for new projects.
With over 10 million weekly downloads, Redux Toolkit has become the standard way to write Redux code. It includes RTK Query, a powerful data fetching and caching solution that eliminates the need to manually write thunks or manage loading states for API calls. The library uses Immer internally to allow writing "mutative" update logic that's transformed into safe immutable updates, making reducer code more intuitive and readable.
import { configureStore, createSlice, createAsyncThunk } from '@reduxjs/toolkit';
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react';
// Define an async thunk for fetching user data
const fetchUserById = createAsyncThunk(
'users/fetchById',
async (userId) => {
const response = await fetch(`https://jsonplaceholder.typicode.com/users/${userId}`);
return response.json();
}
);
// Create a slice with reducers and actions
const userSlice = createSlice({
name: 'user',
initialState: {
profile: null,
status: 'idle',
error: null
},
reducers: {
updateProfile: (state, action) => {
// Direct mutation syntax thanks to Immer
state.profile = { ...state.profile, ...action.payload };
},
clearUser: (state) => {
state.profile = null;
state.status = 'idle';
}
},
extraReducers: (builder) => {
builder
.addCase(fetchUserById.pending, (state) => {
state.status = 'loading';
})
.addCase(fetchUserById.fulfilled, (state, action) => {
state.status = 'succeeded';
state.profile = action.payload;
})
.addCase(fetchUserById.rejected, (state, action) => {
state.status = 'failed';
state.error = action.error.message;
});
}
});
// Define RTK Query API
const postsApi = createApi({
reducerPath: 'postsApi',
baseQuery: fetchBaseQuery({ baseUrl: 'https://jsonplaceholder.typicode.com' }),
endpoints: (builder) => ({
getPosts: builder.query({
query: () => '/posts'
}),
getPostById: builder.query({
query: (id) => `/posts/${id}`
})
})
});
// Configure store with slices and RTK Query
const store = configureStore({
reducer: {
user: userSlice.reducer,
[postsApi.reducerPath]: postsApi.reducer
},
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware().concat(postsApi.middleware)
});
// Export actions and hooks
export const { updateProfile, clearUser } = userSlice.actions;
export const { useGetPostsQuery, useGetPostByIdQuery } = postsApi;
export { fetchUserById };
// Usage in React component:
// const { data: posts, isLoading } = useGetPostsQuery();
// const dispatch = useDispatch();
// dispatch(fetchUserById(1));Single Page Applications with Complex State: Large React applications with authentication, user preferences, shopping carts, and multiple feature domains benefit from Redux Toolkit's slice-based organization. Each feature gets its own slice with co-located reducers and actions, making the codebase more maintainable than scattered action creators and reducer files.
Data-Intensive Dashboards: Applications displaying real-time data from multiple API endpoints can use RTK Query to automatically manage API calls, caching, and cache invalidation. The generated hooks handle loading and error states automatically, reducing hundreds of lines of manual fetch logic to simple query definitions.
Form-Heavy Enterprise Applications: Business applications with complex multi-step forms, validation, and draft state management use createSlice() to manage form state with less code. The built-in Immer integration makes updating deeply nested form fields straightforward without manual object spreading.
Migrating Legacy Redux Codebases: Existing Redux applications can incrementally adopt Redux Toolkit by converting one reducer at a time from traditional switch statements to createSlice(). The package is fully compatible with existing Redux code, allowing gradual modernization without rewriting entire state management layers.
Server-Side Rendered React Applications: Next.js and similar SSR frameworks benefit from Redux Toolkit's configureStore() which handles server-side state hydration and provides consistent middleware configuration across client and server rendering contexts.
👻 Primitive and flexible state management for React
Simple, scalable state management.
Recoil - A state management library for React
🧙 Valtio makes proxy-state simple for React and Vanilla
🐻 Bear necessities for state management in React
npm install @reduxjs/toolkitpnpm add @reduxjs/toolkitbun add @reduxjs/toolkit