Prisma Redis Caching Middleware

raw JSON →
4.8.0 verified Thu Apr 23 auth: no javascript

prisma-redis-middleware is a Prisma middleware designed to cache the results of Prisma queries in Redis, significantly improving application performance by reducing database load. It also provides an in-memory LRU cache as a fallback mechanism. The current stable version is 4.8.0, with frequent patch and minor releases, indicating active development and responsiveness to community needs. Key features include fine-grained cache invalidation, support for custom cache keys, persistence with Redis, and the ability to define specific caching rules for individual Prisma models and methods (e.g., `findUnique`, `findMany`, `count`, `aggregate`, `groupBy`). It allows developers to include or exclude certain models or query methods from being cached, and define custom cache times per model, distinguishing it from simpler caching solutions. The middleware internally leverages `async-cache-dedupe` for efficient request deduplication. Developers must provide their own Redis client implementation, such as `ioredis`, which is a common and recommended choice for robust Redis connectivity.

error Error: Cannot find module 'ioredis'
cause The `ioredis` package (or another Redis client) has not been installed or is not resolvable in your project.
fix
Install ioredis and its types: npm install ioredis @types/ioredis.
error TypeError: prisma.$use is not a function
cause Your `@prisma/client` version is too old and does not support Prisma middleware, or the Prisma client instance (`prisma`) was not correctly initialized before calling `$use`.
fix
Update @prisma/client to a version that supports middleware (Prisma 2.x or newer). Ensure new PrismaClient() is called before attempting to apply middleware.
error Redis connection error: connect ECONNREFUSED <IP>:<PORT>
cause The application failed to establish a connection with the Redis server. This usually means Redis is not running, is inaccessible from your host, or the connection details (host, port, auth) are incorrect.
fix
Verify that your Redis server is running and accessible. Check the Redis client configuration (e.g., REDIS_URL environment variable or explicit options) for correct host, port, and authentication credentials.
error TypeScript error: Argument of type '{ models: { model: string; excludeMethods: string[]; }[]; ... }' is not assignable to parameter of type 'Prisma.Middleware'.
cause This error often occurs when the `Prisma` namespace for types is incorrectly imported or when the options object for `createPrismaRedisCache` is mistakenly passed directly where a `Prisma.Middleware` type (a function) is expected.
fix
Ensure import Prisma from 'prisma'; is used to import the Prisma namespace correctly. The createPrismaRedisCache function returns the middleware function, which is then assigned to a variable typed as Prisma.Middleware.
breaking `prisma-redis-middleware` requires Node.js versions 16.x or 18.x. Older or unsupported Node.js versions may lead to unexpected behavior or runtime errors.
fix Upgrade your Node.js environment to a supported version (16.x or 18.x) as specified in the package's `engines` field.
gotcha This middleware requires a separate Redis client library (e.g., `ioredis`) for Redis storage. It does not bundle one. Failing to install and configure an external client will lead to runtime errors when `type: 'redis'` is selected for storage.
fix Install a compatible Redis client like `ioredis`: `npm install ioredis @types/ioredis` and pass an initialized client instance to the middleware configuration.
gotcha Ensure compatibility between `prisma-redis-middleware` and your `@prisma/client` version. Major Prisma upgrades can introduce breaking changes to the middleware API, potentially requiring an update to this package.
fix Consult the release notes for both `prisma-redis-middleware` and `@prisma/client` to verify compatibility. Update both packages concurrently if necessary, following official documentation.
gotcha Proper cache invalidation, especially with options like `referencesTTL`, requires careful configuration. Misconfigured invalidation strategies can result in stale data being served from the cache, leading to data inconsistencies.
fix Thoroughly test your cache invalidation logic in development. Understand the implications of `cacheTime` for read operations and `referencesTTL` for write-triggered invalidations to prevent stale data.
gotcha The order of applying Prisma middleware via `prisma.$use()` can impact application behavior. If you use other middleware alongside `prisma-redis-middleware`, their interaction might produce unexpected results.
fix Experiment with the order of middleware in your `$use` chain. Caching middleware is often placed early for read operations and strategically for write operations to ensure proper invalidation. Refer to Prisma's middleware documentation for best practices.
npm install prisma-redis-middleware
yarn add prisma-redis-middleware
pnpm add prisma-redis-middleware

Demonstrates how to initialize and apply the Prisma Redis caching middleware with `ioredis`, configuring specific model caching rules, excluding certain methods, and logging cache hits/misses.

import Prisma from "prisma";
import { PrismaClient } from "@prisma/client";
import { createPrismaRedisCache } from "prisma-redis-middleware";
import Redis from "ioredis";

const redis = new Redis(process.env.REDIS_URL || 'redis://localhost:6379'); // Connects to Redis, uses REDIS_URL or default

const prisma = new PrismaClient();

const cacheMiddleware: Prisma.Middleware = createPrismaRedisCache({
  models: [
    { model: "User", excludeMethods: ["findMany"] },
    { model: "Post", cacheTime: 180, cacheKey: "article" },
  ],
  storage: { type: "redis", options: { client: redis, invalidation: { referencesTTL: 300 }, log: console } },
  cacheTime: 300,
  excludeModels: ["Product", "Cart"],
  excludeMethods: ["count", "groupBy"],
  onHit: (key) => {
    console.log("Cache HIT for key:", key);
  },
  onMiss: (key) => {
    console.log("Cache MISS for key:", key);
  },
  onError: (key, error) => {
    console.error("Cache ERROR for key:", key, error);
  }
});

prisma.$use(cacheMiddleware);

async function main() {
  // Example usage: Caching a 'findUnique' query for a 'User' model
  const user = await prisma.user.findUnique({
    where: { id: 1 },
  });
  console.log('Fetched user:', user);

  // Example usage: Querying 'Post' model with custom cache time
  const posts = await prisma.post.findMany();
  console.log('Fetched posts:', posts);
}

main()
  .catch((e) => {
    console.error(e);
    process.exit(1);
  })
  .finally(async () => {
    await prisma.$disconnect();
    redis.disconnect();
  });