Redis session store for Express.js applications using connect-redis middleware
npx @tessl/cli install tessl/npm-connect-redis@9.0.0Connect-Redis provides a Redis-based session store implementation for Express.js applications using the express-session middleware. It enables persistent session storage in Redis databases with support for both standalone Redis clients and Redis clusters, configurable serialization, TTL management, and seamless integration with Express.js applications.
npm install redis connect-redis express-sessionimport { RedisStore } from "connect-redis";
import type { SessionData } from "express-session";For CommonJS:
const { RedisStore } = require("connect-redis");import { RedisStore } from "connect-redis";
import session from "express-session";
import { createClient } from "redis";
// Initialize Redis client
const redisClient = createClient();
await redisClient.connect();
// Initialize RedisStore
const redisStore = new RedisStore({
client: redisClient,
prefix: "myapp:",
});
// Use with express-session
app.use(
session({
store: redisStore,
resave: false,
saveUninitialized: false,
secret: "keyboard cat",
})
);Connect-Redis implements the express-session Store interface, providing:
Creates a new Redis session store instance with the specified configuration.
/**
* Creates a new RedisStore instance
* @param opts - Configuration options for the Redis store
*/
constructor(opts: RedisStoreOptions);
interface RedisStoreOptions {
/** Redis client instance (RedisClientType or RedisClusterType) */
client: any;
/** Key prefix for session keys in Redis (default: "sess:") */
prefix?: string;
/** Count parameter for Redis SCAN operations (default: 100) */
scanCount?: number;
/** Custom serializer for session data (default: JSON) */
serializer?: Serializer;
/** TTL in seconds or function returning TTL (default: 86400) */
ttl?: number | ((sess: SessionData) => number);
/** Disable automatic key expiration (default: false) */
disableTTL?: boolean;
/** Disable TTL reset on session touch (default: false) */
disableTouch?: boolean;
}
interface Serializer {
/** Parse session data from string */
parse(s: string): SessionData | Promise<SessionData>;
/** Serialize session data to string */
stringify(s: SessionData): string;
}Usage Example:
import { RedisStore } from "connect-redis";
import { createClient } from "redis";
const redisClient = createClient({ url: "redis://localhost:6379" });
await redisClient.connect();
// Basic configuration
const store = new RedisStore({
client: redisClient,
});
// Advanced configuration
const advancedStore = new RedisStore({
client: redisClient,
prefix: "myapp:sess:",
ttl: 3600, // 1 hour
scanCount: 200,
disableTouch: true,
serializer: {
parse: JSON.parse,
stringify: JSON.stringify,
},
});
// Dynamic TTL based on session data
const dynamicTTLStore = new RedisStore({
client: redisClient,
ttl: (sess) => {
// VIP users get longer sessions
return sess.user?.type === 'vip' ? 7200 : 3600;
},
});Retrieves session data by session ID.
/**
* Get session data by session ID
* @param sid - Session ID
* @param cb - Optional callback function
* @returns Promise resolving to session data or null if not found
*/
async get(sid: string, cb?: (err?: unknown, data?: any) => any): Promise<any>;Usage Example:
// Promise-based
const sessionData = await store.get("session123");
if (sessionData) {
console.log("Session found:", sessionData);
}
// Callback-based
store.get("session123", (err, data) => {
if (err) {
console.error("Error retrieving session:", err);
} else if (data) {
console.log("Session found:", data);
}
});Stores session data with the specified session ID.
/**
* Store session data with session ID
* @param sid - Session ID
* @param sess - Session data to store
* @param cb - Optional callback function
* @returns Promise resolving when storage is complete
*/
async set(sid: string, sess: SessionData, cb?: (err?: unknown, data?: any) => any): Promise<any>;Usage Example:
const sessionData = {
user: { id: 123, name: "Alice" },
cart: ["item1", "item2"],
cookie: { originalMaxAge: null },
};
// Promise-based
await store.set("session123", sessionData);
// Callback-based
store.set("session123", sessionData, (err) => {
if (err) {
console.error("Error storing session:", err);
} else {
console.log("Session stored successfully");
}
});Updates session TTL without changing session data, used to keep sessions alive.
/**
* Update session TTL without changing data
* @param sid - Session ID
* @param sess - Session data (used for TTL calculation)
* @param cb - Optional callback function
* @returns Promise resolving when touch is complete
*/
async touch(sid: string, sess: SessionData, cb?: (err?: unknown, data?: any) => any): Promise<any>;Deletes a session by session ID.
/**
* Delete session by session ID
* @param sid - Session ID to delete
* @param cb - Optional callback function
* @returns Promise resolving when deletion is complete
*/
async destroy(sid: string, cb?: (err?: unknown, data?: any) => any): Promise<any>;Usage Example:
// Promise-based
await store.destroy("session123");
// Callback-based
store.destroy("session123", (err) => {
if (err) {
console.error("Error destroying session:", err);
} else {
console.log("Session destroyed");
}
});Removes all sessions with the configured prefix.
/**
* Remove all sessions with matching prefix
* @param cb - Optional callback function
* @returns Promise resolving when clearing is complete
*/
async clear(cb?: (err?: unknown, data?: any) => any): Promise<any>;Returns the count of sessions with the configured prefix.
/**
* Get count of sessions with matching prefix
* @param cb - Optional callback function
* @returns Promise resolving to the number of sessions
*/
async length(cb?: (err?: unknown, data?: any) => any): Promise<any>;Returns an array of session IDs (without prefix).
/**
* Get array of session IDs (without prefix)
* @param cb - Optional callback function
* @returns Promise resolving to array of session IDs
*/
async ids(cb?: (err?: unknown, data?: any) => any): Promise<any>;Returns all session data with their IDs.
/**
* Get all session data with IDs
* @param cb - Optional callback function
* @returns Promise resolving to array of session objects with IDs
*/
async all(cb?: (err?: unknown, data?: any) => any): Promise<any>;Bulk Operations Usage Example:
// Get session statistics
const sessionCount = await store.length();
console.log(`Total sessions: ${sessionCount}`);
// Get all session IDs
const sessionIds = await store.ids();
console.log("Session IDs:", sessionIds);
// Get all session data
const allSessions = await store.all();
allSessions.forEach(session => {
console.log(`Session ${session.id}:`, session);
});
// Clear all sessions (use with caution)
await store.clear();interface RedisStoreOptions {
client: any;
prefix?: string;
scanCount?: number;
serializer?: Serializer;
ttl?: number | ((sess: SessionData) => number);
disableTTL?: boolean;
disableTouch?: boolean;
}
interface Serializer {
parse(s: string): SessionData | Promise<SessionData>;
stringify(s: SessionData): string;
}
interface SessionData {
/** Session cookie configuration */
cookie: {
/** Original max age in milliseconds */
originalMaxAge: number | null;
/** Optional expiration date */
expires?: Date | string;
/** Additional cookie properties */
[key: string]: any;
};
/** User-defined session properties */
[key: string]: any;
}
type Callback = (err?: unknown, data?: any) => any;All methods handle Redis connection errors and serialization errors gracefully. When using callbacks, errors are passed as the first parameter. When using Promises, errors are thrown and should be caught:
// Promise-based error handling
try {
const sessionData = await store.get("session123");
} catch (error) {
console.error("Redis error:", error);
}
// Callback-based error handling
store.get("session123", (err, data) => {
if (err) {
console.error("Redis error:", err);
return;
}
// Handle data
});// Static TTL (1 hour)
const store = new RedisStore({
client: redisClient,
ttl: 3600,
});
// Dynamic TTL based on session data
const store = new RedisStore({
client: redisClient,
ttl: (sess) => {
if (sess.user?.premium) return 86400; // 24 hours for premium users
return 3600; // 1 hour for regular users
},
});
// Disable TTL for manual management
const store = new RedisStore({
client: redisClient,
disableTTL: true,
});import { RedisStore } from "connect-redis";
// Custom serializer for compressed sessions
const store = new RedisStore({
client: redisClient,
serializer: {
stringify: (obj) => {
return Buffer.from(JSON.stringify(obj)).toString('base64');
},
parse: (str) => {
return JSON.parse(Buffer.from(str, 'base64').toString());
},
},
});import { createCluster } from "redis";
// Redis cluster configuration
const cluster = createCluster({
rootNodes: [
{ url: "redis://localhost:7000" },
{ url: "redis://localhost:7001" },
{ url: "redis://localhost:7002" },
],
});
await cluster.connect();
const store = new RedisStore({
client: cluster,
prefix: "sessions:",
});