Caching in NestJS

Comprehensive Guide to Caching in NestJS

Cache is a vital part of the modern web application development process as it helps applications to enhance their performance by habitual storing in memory of the frequently used data; this reduces the load on databases and different query APIs. In this tutorial, we're going to look well into how you can implement caching in a NestJS application giving light to all possible caching strategies and use cases.

Table of Contents

  1. Introduction to NestJS
  2. Understanding Caching
  3. Setting Up a NestJS Project
  4. Installing and Configuring Cache Module
  5. Using In-Memory Caching
  6. Implementing Redis Caching
  7. Cache Interceptors
  8. Cache Management
  9. Best Practices
  10. Conclusion

1. Introduction to NestJS

NestJS is a progressive Node.js framework for building efficient, reliable, and scalable server-side applications that leverage TypeScript and are based on a blend of Object-Oriented Programming and Functional Programming techniques.

2. Understanding Caching

Caching is the process of saving files or data copies in a temporary storage location to make the time to access that file or data smaller. Common cases of caching in a web application are to reduce the load on a database, to speed up the response time for data requests made frequently, and to reduce latency from APIs.

3. Setting Up a NestJS Project

Before diving into caching, let's set up a basic NestJS project.

Step 1: Install NestJS CLI

npm install -g @nestjs/cli

Step 2: Create a New Project

nest new nestjs-cache-tutorial

Step 3: Navigate to Project Directory

cd nestjs-cache-tutorial

Step 4: Start the Development Server

npm run start:dev

4. Installing and Configuring Cache Module

NestJS provides a built-in @nestjs/cache-manager package for caching. Let's install and configure it.

Step 1: Install Cache Manager

npm install cache-manager

Step 2: Import CacheModule in AppModule

import { CacheModule, Module } from '@nestjs/common';

@Module({
  imports: [
    CacheModule.register({
      ttl: 5, // seconds
      max: 100, // maximum number of items in cache
    }),
  ],
  controllers: [],
  providers: [],
})
export class AppModule {}

5. Using In-Memory Caching

Step 1: Inject CacheManager

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

@Controller('data')
export class DataController {
  constructor(@Inject(CACHE_MANAGER) private cacheManager: Cache) {}

  @Get()
  async getData() {
    const cachedData = await this.cacheManager.get('key');
    if (cachedData) {
      return cachedData;
    }

    const data = { message: 'Hello, world!' }; // Simulate data fetching
    await this.cacheManager.set('key', data, { ttl: 10 }); // Cache data for 10 seconds
    return data;
  }
}

6. Implementing Redis Caching

Redis is an in-memory data structure store, used as a database, cache, and message broker. Integrating Redis with NestJS enhances caching capabilities.

Step 1: Install Redis and Redis Cache Manager

npm install redis cache-manager-redis-store

Step 2: Configure Redis Cache in AppModule

import { CacheModule, Module } from '@nestjs/common';
import * as redisStore from 'cache-manager-redis-store';

@Module({
  imports: [
    CacheModule.register({
      store: redisStore,
      host: 'localhost',
      port: 6379,
      ttl: 600,
    }),
  ],
  controllers: [],
  providers: [],
})
export class AppModule {}

Step 3: Use Redis Cache in Controller

The usage remains the same as in-memory caching. The only change is the configuration in AppModule.

7. Cache Interceptors

NestJS provides interceptors to implement cross-cutting concerns. Cache Interceptors can automatically handle caching for controller methods.

Step 1: Create a Cache Interceptor

import {
  Injectable,
  CacheInterceptor,
  ExecutionContext,
  CallHandler,
} from '@nestjs/common';
import { Observable } from 'rxjs';

@Injectable()
export class CustomCacheInterceptor extends CacheInterceptor {
  trackBy(context: ExecutionContext): string | undefined {
    const request = context.switchToHttp().getRequest();
    return request.method === 'GET' ? request.url : undefined;
  }
}

Step 2: Apply Cache Interceptor

import { Controller, Get, UseInterceptors } from '@nestjs/common';
import { CustomCacheInterceptor } from './custom-cache.interceptor';

@Controller('data')
@UseInterceptors(CustomCacheInterceptor)
export class DataController {
  @Get()
  getData() {
    return { message: 'Hello, world!' };
  }
}

8. Cache Management

Managing cache involves setting, getting, and clearing cache data as required.

Step 1: Clear Cache Manually

@Controller('data')
export class DataController {
  constructor(@Inject(CACHE_MANAGER) private cacheManager: Cache) {}

  @Get('clear-cache')
  async clearCache() {
    await this.cacheManager.reset();
    return { message: 'Cache cleared' };
  }
}

9. Best Practices

  • TTL Management: Set appropriate TTL values based on the nature of data.
  • Cache Invalidation: Ensure cache is invalidated when underlying data changes.
  • Avoid Over-Caching: Cache only frequently accessed data to avoid memory bloat.
  • Monitor Cache Usage: Use monitoring tools to keep track of cache hit/miss ratios.

10. Conclusion

Implementing caching in a NestJS application can significantly boost performance and scalability. By leveraging in-memory caching and Redis, along with best practices, you can optimize your NestJS applications effectively. With the built-in caching mechanisms and flexibility of custom implementations, NestJS makes it easy to manage cache seamlessly.

Happy coding!

Vibe Plus 1

Sami Rahimi

Innovate relentlessly. Shape the future..

Recent Comments

Post your Comments (first log in)