Что такое CacheModule и кеширование в NestJS?

MiddleNestJS · Backend·Обновлено 17 августа 2026
Коротко
CacheModule — встроенный модуль NestJS на основе cache-manager, который позволяет кешировать данные (ответы контроллеров или произвольные значения) в памяти или во внешнем хранилище вроде Redis, чтобы избежать повторных дорогих вычислений и запросов.

Что такое CacheModule

CacheModule — встроенный модуль NestJS для кеширования данных, построенный поверх пакета cache-manager. Он даёт единый API для сохранения результатов вычислений или запросов в памяти процесса или во внешнем хранилище (Redis, Memcached), чтобы не выполнять повторно дорогие операции.

Подключение и конфигурация

Модуль подключается через CacheModule.register() или CacheModule.registerAsync(), если конфигурация зависит от ConfigService или другого провайдера. По умолчанию используется in-memory хранилище с TTL и лимитом на количество записей.

@Module({
  imports: [
    CacheModule.register({
      ttl: 5000, // время жизни записи, мс
      max: 100,  // максимум записей в кеше
    }),
  ],
})
export class AppModule {}

В production обычно подключают внешнее хранилище через cache-manager-redis-store, чтобы кеш переживал рестарт приложения и был общим для нескольких инстансов сервиса.

Кеширование через CacheInterceptor

Самый простой способ — глобальный или локальный CacheInterceptor, который автоматически кеширует ответы GET-эндпоинтов, используя URL как ключ.

@Controller('posts')
@UseInterceptors(CacheInterceptor)
export class PostsController {
  @Get()
  @CacheTTL(30) // переопределяем TTL для конкретного маршрута
  findAll() {
    return this.postsService.findAll();
  }
}

Ручная работа с кешем через CACHE_MANAGER

Когда нужен более гибкий контроль — условное кеширование, инвалидация, кеширование не только HTTP-ответов, — кеш-менеджер инжектируется напрямую.

@Injectable()
export class PostsService {
  constructor(@Inject(CACHE_MANAGER) private cacheManager: Cache) {}

  async findOne(id: string) {
    const cached = await this.cacheManager.get(`post:${id}`);
    if (cached) return cached;

    const post = await this.repository.findOneBy({ id });
    await this.cacheManager.set(`post:${id}`, post, 60000);
    return post;
  }

  async update(id: string, dto: UpdatePostDto) {
    const post = await this.repository.save({ id, ...dto });
    await this.cacheManager.del(`post:${id}`); // инвалидация при изменении
    return post;
  }
}

Ключевые нюансы

  • CacheInterceptor по умолчанию кеширует только GET-запросы и работает по ключу на основе URL — динамические query-параметры нужно учитывать вручную либо отключать интерцептор для таких маршрутов.
  • TTL и ключ настраиваются как глобально, так и точечно через @CacheTTL и @CacheKey.
  • Для распределённых систем нужен внешний стор (Redis), иначе у каждого инстанса приложения будет свой собственный кеш.
  • Инвалидация — ответственность разработчика: NestJS не отслеживает изменения данных автоматически, при мутациях кеш нужно сбрасывать вручную.

Что хочет услышать интервьюер

Понимание, что CacheModule построен на cache-manager и даёт единый API для разных хранилищ (memory, Redis, Memcached)

Знание способов использования: CacheInterceptor для авто-кеширования GET-запросов и CACHE_MANAGER для ручного управления

Понимание, что инвалидация кеша — ручная ответственность разработчика, а не автоматика фреймворка

Знание декораторов @CacheTTL и @CacheKey для тонкой настройки на уровне конкретного роута

Понимание необходимости внешнего хранилища (Redis) для распределённых и многоинстансных приложений

Пример: Подключение CacheModule с in-memory хранилищем

@Module({
  imports: [
    CacheModule.register({
      ttl: 5000, // время жизни записи, мс
      max: 100,  // максимум записей в кеше
    }),
  ],
})
export class AppModule {}

Пример: Ручное кеширование и инвалидация через CACHE_MANAGER

@Injectable()
export class PostsService {
  constructor(@Inject(CACHE_MANAGER) private cacheManager: Cache) {}

  async findOne(id: string) {
    const cached = await this.cacheManager.get(`post:${id}`);
    if (cached) return cached;

    const post = await this.repository.findOneBy({ id });
    await this.cacheManager.set(`post:${id}`, post, 60000);
    return post;
  }

  async update(id: string, dto: UpdatePostDto) {
    const post = await this.repository.save({ id, ...dto });
    await this.cacheManager.del(`post:${id}`); // инвалидация при изменении
    return post;
  }
}

Типичные ошибки

Кандидат думает, что CacheModule автоматически инвалидирует кеш при изменении данных

Забывают, что CacheInterceptor по умолчанию кеширует только GET-запросы, и пытаются применить его к POST/PUT

Не учитывают, что при нескольких инстансах приложения in-memory кеш не будет общим — нужен внешний стор

Путают глобальный TTL модуля и TTL конкретного маршрута через @CacheTTL, не зная про приоритет настроек

Не задумываются о коллизиях кеш-ключей при динамических query-параметрах, так как по умолчанию ключом служит URL

Лучшие курсы по теме

изображение курса

Docker и Ansible

Антон Ларичев
AI-тренажерыAI-тренажеры
Гарантия
Бонусы
иконка звёздочки рейтинга4.7
3 999 ₽ 6 990 ₽
Подробнее
изображение курса

Node.js с нуля

Антон Ларичев
AI-тренажерыAI-тренажеры
Практика в студииПрактика в студии
Гарантия
Бонусы
иконка звёздочки рейтинга4.8
3 999 ₽ 6 990 ₽
Подробнее
изображение курса

Nest.js с нуля

Антон Ларичев
AI-тренажерыAI-тренажеры
Практика в студииПрактика в студии
Гарантия
Бонусы
иконка звёздочки рейтинга4.6
3 999 ₽ 6 990 ₽
Подробнее