Advanced caching decorators for NestJS applications with support for TTL, conditional caching, stale-while-revalidate, and more.
- 🚀 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
# Using pnpm (recommended)
pnpm add nest-cacheable
# Using npm
npm install nest-cacheable
# Using yarn
yarn add nest-cacheable
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 {}
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);
}
}
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);
}
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);
}
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
})
@Cacheable({
cacheKey: (userId, filters) => [
`user:${userId}`,
`filters:${JSON.stringify(filters)}`,
],
})
async getUserData(userId: string, filters: any) {
// Method implementation
}
@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
}
@Cacheable({
ttl: 60, // Cache for 60 seconds
staleWhileRevalidate: 30, // Serve stale for 30 more seconds
backgroundRefetch: true, // Refresh in background
})
async getFrequentlyAccessedData() {
// Method implementation
}
// 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
}
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 {}
- Choose appropriate TTL values - Consider data freshness requirements
- Use meaningful cache keys - Include all parameters that affect the result
- Monitor cache performance - Use event callbacks to track hit rates
- Handle errors gracefully - Implement
onError
callbacks - Clear cache strategically - Use
@CacheEvict
after data modifications
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 |
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 |
Check the examples/
directory for complete working examples:
- Basic caching
- Redis integration
- Conditional caching
- Cache eviction patterns
- Stale-while-revalidate
Contributions are welcome! Please feel free to submit a Pull Request.
MIT License - see the LICENSE file for details.
For issues and feature requests, please use the GitHub issue tracker.