NextJS 14 Auth with Redux and Superbase
In the ever-evolving landscape of web development, harnessing the power of modern frameworks and tools is key to building efficient, scalable, and dynamic applications. Next.js 14 emerges as a frontrunner, offering unparalleled support for React-based server-side rendering and static site generation, while Redux provides a robust state management solution, ensuring a predictable state across your application. Adding Supabase into the mix, with its easy-to-use and scalable backend services, developers can now leverage the best of both worlds: a powerful frontend with Next.js and Redux, and a flexible, PostgreSQL-powered backend. This blog post aims to demystify the process of integrating these cutting-edge technologies. Whether you're building a full-fledged e-commerce site, a SaaS application, or anything in between, follow along as we explore how to seamlessly use Next.js 14 with Redux and Supabase, unlocking a new horizon of web development possibilities.
Clone, Download or Fork
This is a tutorial on how to use NextJS 14 with Redux and Superbase. This tutorial is a work in progress and will be updated as I continue to work on it. If you would like to see the code, you can find it on my GitHub
Create a new NextJS project
First, we need to create a new NextJS project. We can do this by running the following command in our terminal:
npx create-next-app@latest
Add neccessary dependencies
Next, we need to install the necessary dependencies for our project. We will need the following packages:
project-folder/package.json
{
"name": "project-name",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint"
},
"dependencies": {
"@reduxjs/toolkit": "^1.9.7",
"@supabase/auth-ui-react": "^0.4.6",
"@supabase/auth-ui-shared": "^0.1.8",
"@supabase/ssr": "^0.0.4",
"@supabase/supabase-js": "^2.38.4",
"@vercel/analytics": "^1.1.1",
"next": "14.1.0",
"prismjs": "^1.29.0",
"react": "^18",
"react-dom": "^18",
"react-redux": "^8.1.3"
},
"devDependencies": {
"@types/node": "20.11.17",
"@types/react": "18.2.55",
"eslint": "^8",
"eslint-config-next": "14.1.0",
"sass": "^1.70.0"
}
}
Create Supabase Route
Create a new folder called supabase in the root of your project called supabase and create a file called supabaseRoute.js and add the following code:
project-folder/supabase/supabaseRoute.js
import { createServerClient } from "@supabase/ssr";
import { cookies } from "next/headers";
export function getSupabaseRoute(request) {
const cookieStore = cookies();
return createServerClient(
process.env.NEXT_PUBLIC_SUPABASE_URL,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY,
{
cookies: {
get(name) {
return cookieStore.get(name)?.value;
},
set(name, value, options) {
cookieStore.set({ name, value, ...options });
},
remove(name, options) {
cookieStore.set({ name, value: "", ...options });
},
},
}
);
}
Create Middleware
Create the middleware.ts file in the root of your project and add the following code:
project-folder/middleware.ts
import { createServerClient, type CookieOptions } from "@supabase/ssr";
import { NextResponse, type NextRequest } from "next/server";
export async function middleware(request: NextRequest) {
let response = NextResponse.next({
request: {
headers: request.headers,
},
});
const supabase = createServerClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
{
cookies: {
get(name: string) {
return request.cookies.get(name)?.value;
},
set(name: string, value: string, options: CookieOptions) {
request.cookies.set({
name,
value,
...options,
});
response = NextResponse.next({
request: {
headers: request.headers,
},
});
response.cookies.set({
name,
value,
...options,
});
},
remove(name: string, options: CookieOptions) {
request.cookies.set({
name,
value: "",
...options,
});
response = NextResponse.next({
request: {
headers: request.headers,
},
});
response.cookies.set({
name,
value: "",
...options,
});
},
},
}
);
await supabase.auth.getSession();
return response;
}
Add neccessary dependencies
Next, we need to install the necessary dependencies for our project. We will need the following packages:
project-folder/src/app/_components/redux-provider/ReduxProvider.js
"use client";
import { Provider } from "react-redux";
import { store } from "../../_redux/store";
const ReduxProvider = ({ children }) => {
return <Provider store={store}>{children}</Provider>;
};
export default ReduxProvider;
Create Redux Store
Next, we need to create a Redux store to manage our application state. We will need to create a store file and import the necessary reducers.
project-folder/src/app/_redux/store.js
import { configureStore } from "@reduxjs/toolkit";
import sessionReducer from "./features/session/sessionSlice";
import siteReducer from "./features/site/siteSlice";
export const store = configureStore({
reducer: {
session: sessionReducer,
site: siteReducer,
},
});
Create Redux Session Slice
Next, we will create a new file in the _redux/features/session
folder called sessionSlice.js
. This file will contain the Redux slice that will manage our session state.
project-folder/src/app/_redux/features/session/sessionSlice.js
import { createSlice } from "@reduxjs/toolkit";
const initialState = {
session: null,
};
export const sessionSlice = createSlice({
name: "session",
initialState,
reducers: {
setSession: (state, action) => {
state.session = action.payload;
},
clearSession: (state) => {
state.session = null;
},
},
});
// Action creators are generated for each case reducer function
export const { setSession, clearSession } = sessionSlice.actions;
export default sessionSlice.reducer;