NestJS Cache Manager

repository·master·Indexed 41 days ago

https://github.com/nestjs/cache-manager

A NestJS wrapper for the cache-manager library, providing a drop-in replacement for the deprecated @nestjs/common CacheModule. Version 12.0.0 supports ESM and provides tools like CacheInterceptor for automatic response caching, @CacheKey and @CacheTTL decorators for custom configuration, and support for multiple storage strategies including Keyv and Redis.

Tokens
4.7K
Snippets
17
Records
22
Agent score
50%

What's inside NestJS Cache Manager

  1. Check Node.js requirements for @nestjs/cache-manager

    master

    This package is distributed as ESM only. To avoid ERR_REQUIRE_ESM errors when using require() (which happens in CommonJS applications), you must use a Node.js version where require(esm) is available unflagged.

    Supported Node.js versions:

    • ^20.19.0
    • ^22.12.0
    • >=24.0.0

    If you are using a standard NestJS setup (CommonJS), you can continue using standard import statements; TypeScript will compile them to require(), and the compatible Node.js runtime will handle the ESM loading automatically.

  2. Install @nestjs/cache-manager

    master

    To use caching in your NestJS application, install the @nestjs/cache-manager package along with the underlying cache-manager library.

    This package serves as a drop-in replacement for the deprecated CacheModule that was previously part of @nestjs/common.

    $ npm i --save @nestjs/cache-manager cache-manager
  3. Run Redis via Docker Compose

    master

    This docker-compose.yml file provides a configuration to run a Redis instance, which can be used as a cache store for the @nestjs/cache-manager package. It exposes the default Redis port 6379 to the host machine.

    version: "3"
    
    services:
      redis:
        image: redis
        ports:
          - "6379:6379"
        restart: always
  4. Configure CacheModule options

    master

    The CacheModuleOptions object defines how the cache module is initialized. It combines standard CacheManagerOptions with store-specific configuration and an optional isGlobal flag.

    • isGlobal (optional): If set to true, the CacheModule is registered as a global module, making it available across the entire application without needing to import it into every module.

    Note: Store-specific configuration keys take precedence over general cache module options because of how createCacheManager is implemented.

    const options: CacheModuleOptions = {
      isGlobal: true,
      // ... other CacheManagerOptions and store-specific config
    };
  5. Configure CacheModule options

    master

    The CacheModule is configured using the MODULE_OPTIONS_TOKEN. When setting up the module, you can provide configuration via the register or registerAsync methods. If you are using a factory pattern to provide options, the module expects a method named createCacheOptions to be available on your options factory object.

    // Example of how the module is typically configured using the generated class
    @Module({
      imports: [CacheModule.register({ ttl: 60 })],
    })
    export class AppModule {}
  6. Use the CacheInterceptor

    master

    The CacheInterceptor is the primary tool for implementing automatic response caching in NestJS applications. By applying this interceptor to a controller or a specific route handler, NestJS will automatically cache the response and serve it from the cache for subsequent requests, reducing load on your application logic and data sources.

    To use it, import CacheInterceptor from @nestjs/cache-manager and register it using the @UseInterceptors() decorator.

    import { Controller, Get, UseInterceptors } from '@nestjs/common';
    import { CacheInterceptor } from '@nestjs/cache-manager';
    
    @Controller('users')
    @UseInterceptors(CacheInterceptor) // Applies caching to all routes in this controller
    export class UsersController {
      @Get()
      findAll() {
        return { data: 'this is cached' };
      }
    }
  7. Register the CacheModule statically

    master

    Use CacheModule.register() to configure the cache manager with static options. This is useful when your cache configuration does not depend on any asynchronous providers (like ConfigService). You can pass isGlobal: true in the options to make the CacheModule available globally across your entire application.

    @Module({
      imports: [CacheModule.register({ isGlobal: true, store: myStore, ... })],
    })
    export class AppModule {}
  8. Set custom cache expiration with @CacheTTL()

    master

    Use the @CacheTTL() decorator to define a custom time-to-live (TTL) for cached responses on a specific route handler. The TTL value is specified in milliseconds.

    You can provide a static number or a CacheTTLFactory function. The factory function receives the ExecutionContext and can return a number or a Promise<number>, allowing you to calculate the TTL dynamically based on the request context (e.g., user roles or request headers).

    // Using a static number (5 seconds)
    @CacheTTL(5000)
    @Get()
    async findAll() {}
    
    // Using a dynamic factory
    @CacheTTL((context: ExecutionContext) => {
      const request = context.switchToHttp().getRequest();
      return request.user.isAdmin ? 60000 : 1000;
    })
    @Get()
    async findDynamic() {}
  9. Configure CacheManagerOptions

    master

    The CacheManagerOptions interface defines the configuration for the NestJS cache manager. It allows you to specify storage engines, namespaces, and TTL (Time To Live) behaviors.

    Available Options

    OptionTypeDescription
    storesKeyv | KeyvStoreAdapter | Cacheable | (Keyv | KeyvStoreAdapter)[]The cache storage manager. Defaults to 'memory'. You can provide a single instance or an array of instances for multi-store setups.
    namespacestringA global cache storage namespace. Defaults to keyv. This applies to all KeyvStoreAdapter instances.
    ttlnumberDefault time to live in milliseconds. This is the maximum duration an item remains in the cache before removal.
    refreshThresholdnumberIf set, the system checks the TTL after retrieving a value. If the remaining TTL is less than this threshold, the value is updated asynchronously.
    nonBlockingbooleanIf true, the system will not block when using multiple stores. Defaults to false.
    import { CacheManagerOptions } from '@nestjs/cache-manager';
    
    const options: CacheManagerOptions = {
      stores: [new Keyv(), new KeyvStoreAdapter()],
      namespace: 'my-app',
      ttl: 60000,
      refreshThreshold: 10000,
      nonBlocking: true,
    };
  10. Use CacheModuleAsyncOptions for dynamic configuration

    master

    The CacheModuleAsyncOptions interface allows for dynamic, asynchronous configuration of the CacheModule. It supports three primary patterns for providing configuration:

    1. useClass: Provide a class that implements CacheOptionsFactory. Nest will instantiate this class.
    2. useExisting: Provide an injection token for an existing provider that implements CacheOptionsFactory.
    3. useFactory: Provide a factory function that returns the configuration object (or a Promise of it). This is often used with the inject array to provide dependencies to the factory.

    Additional properties:

    • inject: An array of dependencies to be injected into the useFactory function.
    • extraProviders: An array of additional providers to be registered within the scope of this module.
    • isGlobal: If true, registers the module globally.
    // Example using useFactory
    CacheModule.registerAsync({
      isGlobal: true,
      useFactory: (configService: ConfigService) => {
        return {
          store: 'memory',
          ttl: 60,
        };
      },
      inject: [ConfigService],
    });
    
    // Example using useClass
    CacheModule.registerAsync({
      useClass: MyCacheConfigFactory,
    });
  11. Register the CacheModule asynchronously

    master

    Use CacheModule.registerAsync() to configure the cache manager using asynchronous providers. This is the recommended approach when your cache configuration needs to be fetched from an external source or a NestJS ConfigService. You can also provide extraProviders via the options object to include additional providers in the module.

    @Module({
      imports: [
        CacheModule.registerAsync({
          isGlobal: true,
          useFactory: async (configService: ConfigService) => ({
            store: myStore,
            ttl: configService.get('CACHE_TTL'),
          }),
          inject: [ConfigService],
          extraProviders: [MyCustomProvider],
        }),
      ],
    })
    export class AppModule {}