Skip to content

Advanced caching decorators for NestJS applications with support for TTL, conditional caching, stale-while-revalidate, and more.

License

Notifications You must be signed in to change notification settings

Satyam-2001/NestJs-Cacheable

Repository files navigation

NestJS Cacheable

Advanced caching decorators for NestJS applications with support for TTL, conditional caching, stale-while-revalidate, and more.

Features

  • 🚀 Simple Integration - Easy-to-use decorators for caching method results
  • Performance Optimized - Reduce database queries and API calls
  • 🎯 Conditional Caching - Cache based on custom conditions
  • 🔄 Stale-While-Revalidate - Serve stale content while refreshing in background
  • 🗑️ Cache Eviction - Clear cache entries programmatically
  • 📊 Event Callbacks - Monitor cache hits, misses, and errors
  • 🔧 Customizable - Configure TTL, cache keys, and serialization
  • 🌐 Multiple Stores - Support for Redis, Memory, and other cache stores

Installation

# Using pnpm (recommended)
pnpm add nest-cacheable

# Using npm
npm install nest-cacheable

# Using yarn
yarn add nest-cacheable

Quick Start

1. Import CacheModule

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

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

2. Use Cacheable Decorator

import { Injectable } from '@nestjs/common';
import { Cacheable, Time } from 'nest-cacheable';

@Injectable()
export class UserService {
  @Cacheable({
    ttl: 5 * Time.MINUTE,
    cacheKey: (userId) => `user:${userId}`,
  })
  async getUser(userId: string) {
    // This expensive operation will be cached
    return await this.database.findUser(userId);
  }
}

Decorators

@Cacheable

Cache method results with advanced options:

@Cacheable({
  // Cache expiration time in seconds
  ttl: 60,

  // Custom cache key
  cacheKey: (id) => `product:${id}`,

  // Conditional caching
  cacheIf: (id) => id !== 'admin',

  // Event callbacks
  onHit: (key) => console.log(`Cache hit: ${key}`),
  onMiss: (key) => console.log(`Cache miss: ${key}`),
  onError: (error) => console.error(`Cache error: ${error}`),

  // Stale-while-revalidate
  staleWhileRevalidate: 30,
  backgroundRefetch: true,

  // Background refresh interval
  refetchInterval: 60,

  // Custom serialization
  serialize: (data) => JSON.stringify(data),
  deserialize: (cached) => JSON.parse(cached),
})
async getProduct(id: string) {
  return await this.productRepository.findOne(id);
}

@CacheEvict

Clear cache entries:

@CacheEvict({
  // Cache key to evict
  cacheKey: (id) => `product:${id}`,

  // Clear before method execution
  beforeInvocation: false,

  // Clear all cache entries
  all: false,

  // Exact key match or pattern
  exact: true,
})
async updateProduct(id: string, data: UpdateProductDto) {
  return await this.productRepository.update(id, data);
}

Advanced Usage

Time Utilities

import { Time } from 'nest-cacheable';

@Cacheable({
  ttl: 2 * Time.HOUR,  // 2 hours
  // or
  ttl: 30 * Time.MINUTE,  // 30 minutes
  // or
  ttl: 7 * Time.DAY,  // 7 days
})

Multiple Cache Keys

@Cacheable({
  cacheKey: (userId, filters) => [
    `user:${userId}`,
    `filters:${JSON.stringify(filters)}`,
  ],
})
async getUserData(userId: string, filters: any) {
  // Method implementation
}

Conditional Caching

@Cacheable({
  cacheIf: async (userId) => {
    // Only cache for non-admin users
    const user = await this.getUser(userId);
    return user.role !== 'admin';
  },
})
async getSensitiveData(userId: string) {
  // Method implementation
}

Stale-While-Revalidate Pattern

@Cacheable({
  ttl: 60,  // Cache for 60 seconds
  staleWhileRevalidate: 30,  // Serve stale for 30 more seconds
  backgroundRefetch: true,  // Refresh in background
})
async getFrequentlyAccessedData() {
  // Method implementation
}

Cache Eviction Patterns

// Clear specific cache entry
@CacheEvict({
  cacheKey: (id) => `item:${id}`,
})
async deleteItem(id: string) {
  // Method implementation
}

// Clear all cache entries
@CacheEvict({
  all: true,
})
async clearAllCache() {
  // Method implementation
}

// Clear before method execution
@CacheEvict({
  cacheKey: (id) => `item:${id}`,
  beforeInvocation: true,
})
async updateItem(id: string, data: any) {
  // Method implementation
}

Redis Configuration

For production use, Redis is recommended:

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

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

Best Practices

  1. Choose appropriate TTL values - Consider data freshness requirements
  2. Use meaningful cache keys - Include all parameters that affect the result
  3. Monitor cache performance - Use event callbacks to track hit rates
  4. Handle errors gracefully - Implement onError callbacks
  5. Clear cache strategically - Use @CacheEvict after data modifications

API Reference

CacheableOptions

Option Type Description
ttl number Cache expiration time in seconds
cacheKey string | string[] | Function Custom cache key definition
cacheIf Function Condition to determine if caching should be applied
serialize Function Custom serialization function
deserialize Function Custom deserialization function
staleWhileRevalidate number Time to serve stale content while refreshing
backgroundRefetch boolean Enable background refresh
refetchInterval number Background refresh interval in seconds
onError Function Error callback
onSuccess Function Success callback
onHit Function Cache hit callback
onMiss Function Cache miss callback

CacheEvictOptions

Option Type Description
cacheKey string | string[] | Function Cache key(s) to evict
exact boolean Use exact key match or pattern
beforeInvocation boolean Clear cache before method execution
all boolean Clear all cache entries

Examples

Check the examples/ directory for complete working examples:

  • Basic caching
  • Redis integration
  • Conditional caching
  • Cache eviction patterns
  • Stale-while-revalidate

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

License

MIT License - see the LICENSE file for details.

Support

For issues and feature requests, please use the GitHub issue tracker.

About

Advanced caching decorators for NestJS applications with support for TTL, conditional caching, stale-while-revalidate, and more.

Resources

License

Stars

Watchers

Forks