Caching — In-Memory & Redis

Speed Up Routes With CacheModule

Caching — In-Memory & Redis

@nestjs/cache-manager wraps cache-manager and ships with a CacheInterceptor that auto-caches GET routes.

4 min read Level 2/5 #nestjs#caching#redis
What you'll learn
  • Register CacheModule and tune the TTL
  • Apply @UseInterceptors(CacheInterceptor) to routes
  • Swap the in-memory store for Redis in production

Caching is one of the highest-leverage changes you can make to a Nest app. The built-in CacheModule wraps cache-manager and gives you a CacheInterceptor that transparently caches GET responses.

Register The Module

npm i @nestjs/cache-manager cache-manager
import { Module } from '@nestjs/common';
import { CacheModule } from '@nestjs/cache-manager';

@Module({
  imports: [CacheModule.register({ ttl: 5_000, max: 100 })],
})
export class AppModule {}

ttl is in milliseconds. max caps the number of entries before LRU eviction kicks in.

Auto-Cache A Route

import { CacheInterceptor } from '@nestjs/cache-manager';
import { Controller, Get, UseInterceptors } from '@nestjs/common';

@Controller('products')
@UseInterceptors(CacheInterceptor)
export class ProductsController {
  @Get()
  list() {
    return expensiveQuery();
  }
}

The interceptor keys cache entries by the request URL, so /products and /products?page=2 are cached separately.

Manual Cache Usage

import { Inject, Injectable } from '@nestjs/common';
import { CACHE_MANAGER } from '@nestjs/cache-manager';
import type { Cache } from 'cache-manager';

@Injectable()
export class FeedService {
  constructor(@Inject(CACHE_MANAGER) private cache: Cache) {}

  async getFeed(userId: string) {
    const hit = await this.cache.get<Feed>(`feed:${userId}`);
    if (hit) return hit;
    const feed = await buildFeed(userId);
    await this.cache.set(`feed:${userId}`, feed, 60_000);
    return feed;
  }
}

Swap For Redis

import { redisStore } from 'cache-manager-redis-yet';

CacheModule.registerAsync({
  isGlobal: true,
  useFactory: async () => ({
    store: await redisStore({ url: process.env.REDIS_URL }),
    ttl: 60_000,
  }),
});

Everything else stays the same — the interceptor and CACHE_MANAGER token do not change. That is the value of the abstraction.

Background Jobs With BullMQ →