Creating a Session Store with Redis and Next.js

Learn how to durably store sessions with Vercel KV (Redis) and Next.js.
Last updated on November 6, 2023
FrameworksDatabases & CMS

In this guide, we will learn how to durably store sessions with Vercel KV (Redis) and Next.js.

Sessions are used to persist user data across multiple requests. When a user visits your application, a session is initiated and used to store data related to that particular user. This is useful for maintaining user-specific states and persisting data across the lifecycle of a user's interaction with the application.

For instance, consider a shopping site. Once a user adds an item to their cart, this data can be stored in a session. This allows the user to navigate to different parts of the site, and when they return to their cart, the items are still there. This is made possible by the persistent nature of sessions.

You can store and manage sessions with Redis through Vercel KV. Here is a step-by-step explanation of how to build your own session store.

We start off by importing the necessary modules. We install and import server-only to ensure the server-side code can't be exposed to the client. We import cookies from next/headers to handle the session id cookie, and kv from @vercel/kv to interact with your Vercel KV store.

import "server-only";
import { cookies } from "next/headers";
import { kv } from "@vercel/kv";
Install @vercel/kv to use Redis in your Next.js application.

These functions handle the creation and retrieval of a session id which is unique for each session. This id is used to differentiate between different users or sessions. If a session id does not exist, a new one is created and set into the cookies.

type SessionId = string;
export function getSessionId(): SessionId | undefined {
const cookieStore = cookies();
return cookieStore.get("session-id")?.value;
}
function setSessionId(sessionId: SessionId): void {
const cookieStore = cookies();
cookieStore.set("session-id", sessionId);
}
export function getSessionIdAndCreateIfMissing() {
const sessionId = getSessionId();
if (!sessionId) {
const newSessionId = crypto.randomUUID();
setSessionId(newSessionId);
return newSessionId;
}
return sessionId;
}
Handling creating and setting session IDs.

These functions provide an interface to the Vercel KV store for the session. get is used to retrieve a value for a specific key, getAll is used to retrieve all key-value pairs for a session, and set is used to set a value for a specific key.

session-store.ts
export function get(key: string, namespace: string = "") {
const sessionId = getSessionId();
if (!sessionId) {
return null;
}
return kv.hget(`session-${namespace}-${sessionId}`, key);
}
export function getAll(namespace: string = "") {
const sessionId = getSessionId();
if (!sessionId) {
return null;
}
return kv.hgetall(`session-${namespace}-${sessionId}`);
}
export function set(key: string, value: string, namespace: string = "") {
const sessionId = getSessionIdAndCreateIfMissing();
return kv.hset(`session-${namespace}-${sessionId}`, { [key]: value });
}
Setting and retrieving sessions.

Remember that the 'key' here represents a particular piece of data you want to store, like 'username' or 'cart-items'. The 'namespace' is an optional argument that you can use to further segregate your data.

To use this code in your Next.js application, import the functions provided in this module wherever you need to set or get session data. For example:

import { get, set } from './session-store';
// Storing a user's name in the session
await set('username', 'John Doe');
// Getting the user's name from the session
const username = await get('username');
console.log(username); // Outputs: 'John Doe'
Using the newly created session store.

This example sets the username 'John Doe' to the session and retrieves it later. It demonstrates a basic usage of the session store we just created. You can store and retrieve any kind of data as required by your application.

get() can be called from React Server Components, Server Actions, and Route Handlers. set() can be called from Server Actions or Route Handlers. We recommend using Server Actions.

Couldn't find the guide you need?