Advanced caching decorators for NestJS applications with support for TTL, conditional caching, stale-while-revalidate, and more
npm install nest-cacheablebash
Using pnpm (recommended)
pnpm add nest-cacheable
Using npm
npm install nest-cacheable
Using yarn
yarn add nest-cacheable
`
Quick Start
$3
`typescript
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 {}
`
$3
`typescript
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
$3
Cache method results with advanced options:
`typescript
@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);
}
`
$3
Clear cache entries:
`typescript
@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
$3
`typescript
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
})
`
$3
`typescript
@Cacheable({
cacheKey: (userId, filters) => [
user:${userId},
filters:${JSON.stringify(filters)},
],
})
async getUserData(userId: string, filters: any) {
// Method implementation
}
`
$3
`typescript
@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
}
`
$3
`typescript
@Cacheable({
ttl: 60, // Cache for 60 seconds
staleWhileRevalidate: 30, // Serve stale for 30 more seconds
backgroundRefetch: true, // Refresh in background
})
async getFrequentlyAccessedData() {
// Method implementation
}
`
$3
`typescript
// 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:
`typescript
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
$3
| 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 |
$3
| 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: