The official, opinionated, batteries-included toolset for efficient Redux development
—
Redux Toolkit's store configuration provides a simplified API over Redux's createStore() with sensible defaults, automatic middleware setup, and enhanced developer experience features.
Creates a Redux store with good defaults including Redux Thunk, Redux DevTools integration, and development-time invariant checking middleware.
/**
* A friendly abstraction over Redux's createStore() with good defaults
* @param options - Configuration options for the store
* @returns Enhanced Redux store with thunk support and additional methods
*/
function configureStore<
S = any,
A extends Action = AnyAction,
M extends Middlewares<S> = Middlewares<S>,
E extends Enhancers = Enhancers
>(options: ConfigureStoreOptions<S, A, M, E>): EnhancedStore<S, A, E>;
interface ConfigureStoreOptions<S, A extends Action, M extends Middlewares<S>, E extends Enhancers, P = S> {
/** Root reducer or reducer map object */
reducer: Reducer<S, A> | ReducersMapObject<S, A>;
/** Callback to customize middleware array (receives getDefaultMiddleware) */
middleware?: ((getDefaultMiddleware: GetDefaultMiddleware<S>) => M) | M;
/** Enable Redux DevTools (default: true in development) */
devTools?: boolean | DevToolsOptions;
/** Initial state value */
preloadedState?: P;
/** Callback to customize store enhancers */
enhancers?: ((getDefaultEnhancers: GetDefaultEnhancers<S>) => E) | E;
}
interface EnhancedStore<S = any, A extends Action = AnyAction, E = any> extends Store<S, A> {
/** Dispatch function with thunk support */
dispatch: Dispatch<A> & ThunkDispatch<S, any, A>;
}Usage Examples:
import { configureStore } from '@reduxjs/toolkit';
import counterSlice from './features/counter/counterSlice';
import todosSlice from './features/todos/todosSlice';
// Basic store setup
const store = configureStore({
reducer: {
counter: counterSlice.reducer,
todos: todosSlice.reducer
}
});
// Custom middleware configuration
const store = configureStore({
reducer: rootReducer,
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware({
serializableCheck: {
ignoredActions: ['persist/PERSIST']
}
}).concat(logger),
devTools: process.env.NODE_ENV !== 'production'
});
// With preloaded state
const store = configureStore({
reducer: rootReducer,
preloadedState: {
counter: { value: 5 },
todos: []
}
});
export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;
export default store;Get the default middleware array that includes Redux Thunk and development-time checking middleware.
/**
* Returns the default middleware array used by configureStore
* @param options - Options to customize the default middleware
* @returns Array of middleware functions
*/
interface GetDefaultMiddleware<S> {
<O extends MiddlewareOptions<S>>(options?: O): Tuple<DefaultMiddlewareArray<S, O>>;
}
interface MiddlewareOptions<S> {
/** Enable thunk middleware (default: true) */
thunk?: boolean | ThunkOptions<S>;
/** Enable immutable state invariant middleware (default: true in development) */
immutableCheck?: boolean | ImmutableStateInvariantMiddlewareOptions;
/** Enable serializable state invariant middleware (default: true in development) */
serializableCheck?: boolean | SerializableStateInvariantMiddlewareOptions;
/** Enable action creator invariant middleware (default: true in development) */
actionCreatorCheck?: boolean | ActionCreatorInvariantMiddlewareOptions;
}
type DefaultMiddlewareArray<S, O extends MiddlewareOptions<S>> = [
ThunkMiddleware<S>,
...ConditionalMiddleware<O['immutableCheck'], ImmutableStateInvariantMiddleware<S>>,
...ConditionalMiddleware<O['serializableCheck'], SerializableStateInvariantMiddleware>,
...ConditionalMiddleware<O['actionCreatorCheck'], ActionCreatorInvariantMiddleware>
];Usage Examples:
import { configureStore, getDefaultMiddleware } from '@reduxjs/toolkit';
import logger from 'redux-logger';
// Add custom middleware to defaults
const store = configureStore({
reducer: rootReducer,
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware()
.prepend(
// Correctly typed middleware can be added before
rateLimitMiddleware({ requests: 5, window: 1000 })
)
.concat(
// And after the defaults
logger
)
});
// Customize default middleware options
const store = configureStore({
reducer: rootReducer,
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware({
thunk: {
extraArgument: { api, analytics }
},
serializableCheck: {
ignoredActions: ['persist/PERSIST', 'persist/REHYDRATE']
}
})
});
// Disable development middleware in production
const store = configureStore({
reducer: rootReducer,
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware({
immutableCheck: process.env.NODE_ENV !== 'production',
serializableCheck: process.env.NODE_ENV !== 'production'
})
});Configure store enhancers for additional functionality like persistence or analytics.
/**
* Get default store enhancers (auto-batching by default)
* @param options - Options to customize enhancers
* @returns Array of store enhancers
*/
interface GetDefaultEnhancers<S> {
<O extends EnhancerOptions>(options?: O): Tuple<DefaultEnhancerArray<S, O>>;
}
interface EnhancerOptions {
/** Enable auto-batching enhancer (default: true) */
autoBatch?: boolean | AutoBatchOptions;
}
type DefaultEnhancerArray<S, O extends EnhancerOptions> = [
...ConditionalEnhancer<O['autoBatch'], AutoBatchEnhancer>
];
/** Store enhancer for automatic action batching */
function autoBatchEnhancer(options?: AutoBatchOptions): StoreEnhancer;
interface AutoBatchOptions {
/** Custom batch type checker */
type?: 'tick' | 'timer' | 'callback' | ((action: Action) => boolean);
}Usage Examples:
import { configureStore, autoBatchEnhancer } from '@reduxjs/toolkit';
import { persistStore, persistReducer } from 'redux-persist';
// Add persistence enhancer
const persistConfig = {
key: 'root',
storage,
};
const persistedReducer = persistReducer(persistConfig, rootReducer);
const store = configureStore({
reducer: persistedReducer,
enhancers: (getDefaultEnhancers) =>
getDefaultEnhancers().concat(
// Add your custom enhancers here
)
});
// Custom auto-batching configuration
const store = configureStore({
reducer: rootReducer,
enhancers: (getDefaultEnhancers) =>
getDefaultEnhancers({
autoBatch: { type: 'tick' }
})
});Redux Toolkit includes several development-time middleware for catching common mistakes.
/**
* Middleware that detects mutations to state
* @param options - Configuration options
* @returns Middleware function
*/
function createImmutableStateInvariantMiddleware<S = any>(
options?: ImmutableStateInvariantMiddlewareOptions
): Middleware<{}, S>;
interface ImmutableStateInvariantMiddlewareOptions {
/** Enable the middleware */
isImmutable?: (value: any) => boolean;
/** Paths to ignore when checking for mutations */
ignoredPaths?: string[];
/** Function to determine if checking should be ignored */
warnAfter?: number;
}
/**
* Middleware that detects non-serializable values in state and actions
* @param options - Configuration options
* @returns Middleware function
*/
function createSerializableStateInvariantMiddleware(
options?: SerializableStateInvariantMiddlewareOptions
): Middleware<{}, any>;
interface SerializableStateInvariantMiddlewareOptions {
/** Actions to ignore when checking */
ignoredActions?: string[];
/** Action paths to ignore */
ignoredActionPaths?: string[];
/** State paths to ignore */
ignoredPaths?: string[];
/** Function to determine if value is serializable */
isSerializable?: (value: any) => boolean;
/** Function to get entries from value for checking */
getEntries?: (value: any) => [string, any][];
/** Execution time warning threshold */
warnAfter?: number;
}
/**
* Middleware that validates action creators are not called incorrectly
* @param options - Configuration options
* @returns Middleware function
*/
function createActionCreatorInvariantMiddleware(
options?: ActionCreatorInvariantMiddlewareOptions
): Middleware;
interface ActionCreatorInvariantMiddlewareOptions {
/** Enable the middleware */
isActionCreator?: (action: any) => boolean;
}Usage Examples:
import {
configureStore,
createImmutableStateInvariantMiddleware,
createSerializableStateInvariantMiddleware
} from '@reduxjs/toolkit';
const store = configureStore({
reducer: rootReducer,
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware({
// Configure immutable check
immutableCheck: {
ignoredPaths: ['items.dates'],
warnAfter: 128
},
// Configure serializable check
serializableCheck: {
ignoredActions: ['persist/PERSIST', 'persist/REHYDRATE'],
ignoredPaths: ['items.map'],
warnAfter: 128
}
})
});/**
* Extended Redux store with additional typing for thunk dispatch
*/
interface EnhancedStore<S = any, A extends Action = AnyAction, E = any> extends Store<S, A> {
dispatch: Dispatch<A> & ThunkDispatch<S, any, A>;
}
/**
* Configuration options for configureStore
*/
interface ConfigureStoreOptions<S, A extends Action, M extends Middlewares<S>, E extends Enhancers, P = S> {
reducer: Reducer<S, A> | ReducersMapObject<S, A>;
middleware?: ((getDefaultMiddleware: GetDefaultMiddleware<S>) => M) | M;
devTools?: boolean | DevToolsOptions;
preloadedState?: P;
enhancers?: ((getDefaultEnhancers: GetDefaultEnhancers<S>) => E) | E;
}
/**
* Redux DevTools configuration options
*/
interface DevToolsOptions {
/** Custom action name mapping */
actionCreators?: ActionCreatorMapObject;
/** Maximum number of actions to keep */
maxAge?: number;
/** Actions to skip in DevTools */
actionSanitizer?: (action: Action, id: number) => Action;
/** State sanitizer for DevTools */
stateSanitizer?: <S>(state: S, index: number) => S;
/** Trace option */
trace?: boolean;
/** Trace limit */
traceLimit?: number;
}// store/index.ts - Main store configuration
import { configureStore } from '@reduxjs/toolkit';
import { rootReducer } from './rootReducer';
export const store = configureStore({
reducer: rootReducer,
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware({
serializableCheck: {
ignoredActions: ['persist/PERSIST', 'persist/REHYDRATE']
}
})
});
export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;
// store/rootReducer.ts - Combined reducers
import { combineReducers } from '@reduxjs/toolkit';
import counterSlice from '../features/counter/counterSlice';
import todosSlice from '../features/todos/todosSlice';
export const rootReducer = combineReducers({
counter: counterSlice.reducer,
todos: todosSlice.reducer
});const store = configureStore({
reducer: rootReducer,
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware({
// Disable dev middleware in production
immutableCheck: __DEV__,
serializableCheck: __DEV__,
thunk: {
extraArgument: { api, logger }
}
}),
devTools: __DEV__ && {
actionSanitizer: (action) => ({
...action,
// Remove sensitive data from DevTools
payload: action.type.includes('auth') ? '***' : action.payload
})
}
});Install with Tessl CLI
npx tessl i tessl/npm-reduxjs--toolkit