
Using Redis in NestJS
Overriding the NestJS Cache system with RedisI recently implemented Redis within one of my backend NestJS APIs and encountered several headaches. I’m writing this post to help others quickly implement it; as of the time of writing, the proper configuration is not in the NestJS Caching docs. The solution is relatively simple, so this will be a brief post.
Setup
NestJS Cache docs state to use
cache-manager-redis
. However, upon going to the npm page for the package, there’s an alert that it’s deprecated in favor ofKeyv
- which we will be using instead.
- Install:
@keyv/redis
We will be following the direct documentation from Keyv integration for NestJS - Link
- Create file:
cache.module.ts
import { Module } from '@nestjs/common'
import { Cacheable } from 'cacheable'
import { CacheService } from './cache.service'
import KeyvRedis from '@keyv/redis'
import { ConfigModule, ConfigService } from '@nestjs/config'
@Module({
imports: [ConfigModule],
providers: [
{
provide: 'CACHE_INSTANCE',
useFactory: (configService: ConfigService) => {
const redisUrl = configService.get<string>('REDIS_URL')
const secondary = new KeyvRedis(redisUrl)
return new Cacheable({ secondary, ttl: '4h' })
},
inject: [ConfigService],
},
CacheService,
],
exports: ['CACHE_INSTANCE', CacheService],
})
export class CacheModule {}
- Create
cache.service.ts
import { Inject, Injectable } from '@nestjs/common'
import type { Cacheable } from 'cacheable'
@Injectable()
export class CacheService {
constructor(@Inject('CACHE_INSTANCE') private readonly cache: Cacheable) {}
async get<T>(key: string): Promise<T> {
return await this.cache.get(key)
}
async set<T>(key: string, value: T, ttl?: number | string): Promise<void> {
await this.cache.set(key, value, ttl)
}
async delete(key: string): Promise<void> {
await this.cache.delete(key)
}
}
- You are practically finished here. Don’t forget to import the
CacheModule
into yourapp.module.ts
Example Usage
import { Controller, Get } from '@nestjs/common';
import { CacheService } from '../cache/cache.service';
@Controller('sample')
export class SampleController {
constructor(private readonly cacheService: CacheService) {}
@Get()
async sampleQuery() {
const CACHE_KEY = 'sample-health-check';
let cacheHit = null;
let data;
data = await this.cacheService.get(CACHE_KEY);
if (data) {
cacheHit = true;
} else {
await new Promise(resolve => setTimeout(resolve, 1000)) // Simulation of API req
data = 'Example Data'
cacheHit = false
await this.cacheService.set(CACHE_KEY, data)
}
return {
data,
cacheHit,
};
}
}