DEV Community

Cover image for Setting Up Redux in Next.js 15 with Typescript
Saiful Islam
Saiful Islam

Posted on

1

Setting Up Redux in Next.js 15 with Typescript

When working with global state management in Next.js 15, integrating Redux efficiently is crucial. Instead of directly wrapping the entire app inside Provider, it's best to create a dedicated provider component that manages Redux (and other global providers). This ensures better modularity, scalability, and cleaner architecture.

In this blog, we’ll set up Redux in Next.js 15 with a structured provider approach.


1️⃣ Creating the Root Layout (RootLayout.tsx)

The RootLayout.tsx file is the entry point for our Next.js application. Here, we wrap the app inside a custom MainProvider, which will hold all global providers (Redux, Auth, Theme, etc.).

export default function RootLayout({
  children,
}: Readonly<{ children: React.ReactNode }>) {
  return (
    <html lang="en" className="dark" style={{ colorScheme: "dark" }}>
      <body className="antialiased w-full min-h-screen overflow-x-hidden">
        <MainProvider>{children}</MainProvider>
      </body>
    </html>
  );
}
Enter fullscreen mode Exit fullscreen mode

πŸ’‘ Why use MainProvider?

This approach ensures that all global providers are separated from the layout, making it easier to manage and extend.


2️⃣ Creating MainProvider.tsx

The MainProvider component serves as the central place to wrap all providers. Currently, it only includes ReduxProvider, but you can add Auth, Theme, or other providers later.

"use client";
import ReduxProvider from "./ReduxProvider";

const MainProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
  return <ReduxProvider>{children}</ReduxProvider>;
};

export default MainProvider;
Enter fullscreen mode Exit fullscreen mode

πŸš€ Modular Architecture

This approach ensures we can extend providers easily in the future without modifying RootLayout.tsx.


3️⃣ Setting Up ReduxProvider.tsx

Next, we create ReduxProvider.tsx, which initializes Redux and ensures the store remains persistent.

"use client";
import { useRef } from "react";
import { Provider } from "react-redux";
import { store, AppStore } from "@/lib/redux/store";

const ReduxProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
  const storeRef = useRef<AppStore | null>(null);

  if (!storeRef.current) {
    storeRef.current = store();
  }

  return <Provider store={storeRef.current}>{children}</Provider>;
};

export default ReduxProvider;
Enter fullscreen mode Exit fullscreen mode

βœ… Why useRef?

We use useRef to prevent reinitializing the Redux store on every render, ensuring better performance.


4️⃣ Setting Up Redux Store (store.ts)

Now, let’s configure our Redux store inside lib/redux/store.ts.

import { configureStore } from "@reduxjs/toolkit";
import favoriteReducer from "./features/favorite/favoriteSlice";

export const store = () => {
  return configureStore({
    reducer: {
      favorite: favoriteReducer,
    },
  });
};

export type AppStore = ReturnType<typeof store>;
export type RootState = ReturnType<AppStore["getState"]>;
export type AppDispatch = AppStore["dispatch"];
Enter fullscreen mode Exit fullscreen mode

πŸ”₯ Dynamic Store Initialization

Instead of exporting a singleton store, we use a factory function (store()), which allows Next.js server actions and middleware integration.


5️⃣ Creating Hooks for Redux (redux.hooks.ts)

Instead of importing useDispatch and useSelector directly, let’s create typed Redux hooks.

import { useDispatch, useSelector, useStore } from "react-redux";
import type { RootState, AppDispatch, AppStore } from "@/lib/redux/store";

export const useAppDispatch = useDispatch.withTypes<AppDispatch>();
export const useAppSelector = useSelector.withTypes<RootState>();
export const useAppStore = useStore.withTypes<AppStore>();
Enter fullscreen mode Exit fullscreen mode

πŸ›  Typed Redux Hooks

This ensures better TypeScript support and avoids repetitive type definitions.


6️⃣ Creating a Redux Slice (favoriteSlice.ts)

Let’s create a Redux slice for handling favorite items inside features/favorite/favoriteSlice.ts.

import { createSlice, nanoid, type PayloadAction } from "@reduxjs/toolkit";
import { useAppSelector } from "@/hooks/redux.hooks";

interface FavoriteProductType {}

interface InitialStateType = {
  favoriteProduct: FavoriteProductType[]
};

const initialState: InitialStateType = {};

const favoriteSlice = createSlice({
  name: "favorites",
  initialState,
  reducers: {
    addFavorite: (state, action: PayloadAction<FavoriteProductType>) => {}
  },
});

export const useFavoriteProduct = () =>
  useAppSelector((state) => state.favorite);

export const { addFavorite } = favoriteSlice.actions;
export default favoriteSlice.reducer;
Enter fullscreen mode Exit fullscreen mode

πŸ›’ Scalable State Management

Using Redux slices ensures better modularity when adding new features.


Conclusion

By following this structured approach, we’ve successfully integrated Redux into Next.js 15 while keeping the architecture clean and scalable.

πŸ”Ή Key Takeaways:
βœ… Use a dedicated MainProvider to wrap all global providers.
βœ… Use a factory function for Redux store to allow future scalability.
βœ… Create typed Redux hooks for better TypeScript support.
βœ… Use useRef in ReduxProvider to prevent unnecessary reinitialization.

Now, Redux is seamlessly integrated into Next.js 15! πŸš€


Previous Blogs You Might Find Useful

πŸ“Œ Next.js 15 API Error Handling
πŸ“Œ Zod Validation in Next.js 15

Quadratic AI

Quadratic AI – The Spreadsheet with AI, Code, and Connections

  • AI-Powered Insights: Ask questions in plain English and get instant visualizations
  • Multi-Language Support: Seamlessly switch between Python, SQL, and JavaScript in one workspace
  • Zero Setup Required: Connect to databases or drag-and-drop files straight from your browser
  • Live Collaboration: Work together in real-time, no matter where your team is located
  • Beyond Formulas: Tackle complex analysis that traditional spreadsheets can't handle

Get started for free.

Watch The Demo πŸ“Šβœ¨

Top comments (0)

AWS Q Developer image

Your AI Code Assistant

Generate and update README files, create data-flow diagrams, and keep your project fully documented. Built to handle large projects, Amazon Q Developer works alongside you from idea to production code.

Get started free in your IDE

πŸ‘‹ Kindness is contagious

Please show some love ❀️ or share a kind word in the comments if you found this useful!

Got it!