This document covers the complete integration and production-grade architecture for Redis-based caching and rate limiting inside an Express / Node.js backend using TypeScript. Each step is self-contained and production-tested.


Step 1: Install Dependencies

Install the Redis client driver, the Express rate-limiting library, and its Redis storage adapter. All three are required for both the rate limiter and the cache middleware.

bun add ioredis express-rate-limit rate-limit-redis
Package Purpose
ioredis Full-featured Redis client with TypeScript support, pipelining, and cluster mode
express-rate-limit Middleware for enforcing request rate limits on Express routes
rate-limit-redis Storage adapter that backs express-rate-limit with Redis instead of in-process memory

Step 2: Redis Connection Utility

File: src/utils/redis.ts

import { Redis } from 'ioredis';

const redisUrl = process.env.REDIS_URL;

if (!redisUrl) {
  console.warn(
    'REDIS_URL is not defined. Caching and rate limiting will be disabled.'
  );
}

export const redis = redisUrl ? new Redis(redisUrl) : null;

Key design decisions:


Step 3: Rate Limiter Middleware

File: src/middleware/rateLimiter.ts

import rateLimit from 'express-rate-limit';
import RedisStore from 'rate-limit-redis';
import { redis } from '@/utils/redis';

interface LimiterOptions {
  windowMs: number;
  limit: number;
  message: string;
}

export const createRateLimiter = (options: LimiterOptions) => {
  return rateLimit({
    windowMs: options.windowMs,
    limit: options.limit,
    standardHeaders: 'draft-7',
    legacyHeaders: false,
    message: { message: options.message },
    store: redis
      ? new RedisStore({
          sendCommand: (...args: string[]) =>
            redis.call(args[0], ...args.slice(1)),
        })
      : undefined,
  });
};

// Global limiter — applied to all routes
export const globalLimiter = createRateLimiter({
  windowMs: 15 * 60 * 1000, // 15 minutes
  limit: 200,
  message: 'Too many requests. Please try again after 15 minutes.',
});

// Submission limiter — applied to form submission or write endpoints
export const submissionLimiter = createRateLimiter({
  windowMs: 10 * 1000, // 10 seconds
  limit: 1,
  message: 'Too many submissions. Try again after 10 seconds.',
});

How Rate Limiting Works

express-rate-limit tracks request counts per client identifier (defaulting to req.ip). On each incoming request: