Advanced and intelligent caching for Node.js using ioredis and queueing.
Frache is a powerful, feature-rich caching library that provides intelligent caching strategies, warmup tasks, and advanced Redis operations for Node.js applications. Built with TypeScript and designed for production use.
- Simple API:
set(),get(),del(),clear()with intuitive options - Singleton Pattern: Thread-safe singleton with custom Redis client support
- TypeScript First: Full TypeScript support with comprehensive type definitions
- Flexible TTL: Per-key TTL with intelligent defaults
- Namespace Support: Organize cache keys with namespaces
- Cache-aside Pattern:
getOrSet()for seamless cache-aside implementation - Compression: Automatic compression for large values
- Serialization: Smart JSON serialization with fallback handling
- Tag-based Invalidation: Group and invalidate related cache entries
- Batch Operations:
setMany(),getMany(),delMany()for efficiency
- Warmup Tasks: Proactive cache warming with priority queues
- Data Structures: Lists, sets, counters with Redis-native operations
- Memory Management: Intelligent memory usage with configurable limits
- Event System: Comprehensive event emission for monitoring
- Statistics: Built-in performance metrics and hit/miss tracking
- Performance Metrics: Hit rates, response times, memory usage
- Event Listeners: Cache hits, misses, errors, warmup events
- Health Checks: Built-in health monitoring
- Debug Support: Comprehensive logging and error handling
npm install frache ioredisimport { Cache } from 'frache';
// Initialize cache (singleton)
const cache = Cache.getInstance({
defaultTtl: 3600, // 1 hour
defaultNamespace: 'myapp',
});
// Basic operations
await cache.set('user:123', { name: 'John', age: 30 });
const user = await cache.get('user:123');
await cache.del('user:123');
// Cache-aside pattern
const user = await cache.getOrSet('user:456', async () => {
return await database.getUser(456);
}, { ttl: 1800 });import { AdvancedCache } from 'frache';
const cache = AdvancedCache.getInstance();
// Batch operations
await cache.setMany([
{ key: 'user:1', value: { name: 'Alice' } },
{ key: 'user:2', value: { name: 'Bob' } },
]);
const users = await cache.getMany(['user:1', 'user:2']);
// Data structures
await cache.listPush('recent-users', 'user:123');
await cache.setAdd('active-users', 'user:456');
await cache.increment('page-views', 1);
// Tag-based invalidation
await cache.set('product:1', product, { tags: ['products', 'category:electronics'] });
await cache.clear({ tags: ['products'] }); // Clear all product cachePerfect for database caching scenarios:
class UserService {
async getUser(id: number) {
return cache.getOrSet(`user:${id}`, async () => {
// This only runs on cache miss
return await database.users.findById(id);
}, {
ttl: 3600,
tags: ['users', `user:${id}`]
});
}
async updateUser(id: number, data: any) {
const user = await database.users.update(id, data);
// Invalidate related cache
await cache.clear({ tags: [`user:${id}`] });
return user;
}
}Proactively warm your cache for better performance:
// Register warmup tasks
cache.registerWarmupTask({
id: 'popular-products',
name: 'Cache Popular Products',
priority: 1,
execute: async () => {
const products = await database.getPopularProducts();
for (const product of products) {
await cache.set(`product:${product.id}`, product, { ttl: 7200 });
}
}
});
// Queue for execution
cache.queueWarmupTask('popular-products');
// Or run immediately
await cache.runWarmupTask('popular-products');// Listen to cache events
cache.on('hit', (event) => {
console.log(`Cache hit: ${event.key}`);
});
cache.on('miss', (event) => {
console.log(`Cache miss: ${event.key}`);
});
cache.on('warmup', (event) => {
console.log(`Warmup task ${event.data.task.name}: ${event.data.status}`);
});
// Get performance statistics
const stats = cache.getStats();
console.log(`Hit rate: ${(stats.hits / (stats.hits + stats.misses) * 100).toFixed(2)}%`);const cache = Cache.getInstance({
// Redis configuration
redis: new Redis('redis://localhost:6379'),
// Cache settings
defaultTtl: 3600,
defaultNamespace: 'myapp',
keyPrefix: 'cache',
// Performance settings
enableCompression: true,
maxMemory: 100 * 1024 * 1024, // 100MB
// Warmup settings
enableWarmup: true,
warmupInterval: 60000, // 1 minute
});Frache is built with a clean, extensible architecture:
- Cache: Core caching functionality with singleton pattern
- AdvancedCache: Extended functionality with data structures
- Utils: Serialization, compression, key generation utilities
- Types: Comprehensive TypeScript definitions
- Events: Event-driven architecture for monitoring
Frache is designed for high performance:
- Memory Efficient: Smart compression and TTL management
- Network Optimized: Batch operations reduce Redis round trips
- CPU Friendly: Efficient serialization and key generation
- Scalable: Singleton pattern prevents connection proliferation
Cache Operations (1000 iterations):
βββ set(): ~0.5ms avg
βββ get(): ~0.3ms avg (hit)
βββ getOrSet(): ~0.4ms avg (hit), ~15ms avg (miss)
βββ batch operations: ~60% faster than individual calls
| Method | Description | Example |
|---|---|---|
set(key, value, options?) |
Store a value | cache.set('key', 'value', { ttl: 300 }) |
get(key, options?) |
Retrieve a value | cache.get('key') |
del(key, options?) |
Delete a value | cache.del('key') |
clear(options?) |
Clear multiple values | cache.clear({ namespace: 'users' }) |
getOrSet(key, factory, options?) |
Cache-aside pattern | cache.getOrSet('key', () => fetchData()) |
| Method | Description | Example |
|---|---|---|
setMany(entries) |
Set multiple values | cache.setMany([{key: 'k1', value: 'v1'}]) |
getMany(keys) |
Get multiple values | cache.getMany(['k1', 'k2']) |
increment(key, amount?) |
Increment counter | cache.increment('views', 1) |
listPush(key, value) |
Add to list | cache.listPush('queue', item) |
setAdd(key, value) |
Add to set | cache.setAdd('tags', 'important') |
| Method | Description | Example |
|---|---|---|
registerWarmupTask(task) |
Register warmup task | cache.registerWarmupTask({id: 'task1', ...}) |
queueWarmupTask(id, options?) |
Queue task for execution | cache.queueWarmupTask('task1') |
runWarmupTask(id) |
Run task immediately | cache.runWarmupTask('task1') |
- Express + SQLite Example: Complete Express.js application with SQLite database
- Basic Usage: Simple caching examples
- Advanced Patterns: Complex caching strategies
Frache includes comprehensive tests:
npm test # Run all tests
npm run test:watch # Watch mode
npm run test:coverage # Coverage reportTest Coverage: 96+ tests covering all functionality
We welcome contributions! Please see our Contributing Guide for details.
MIT Β© Benjamin Weller
Made with β€οΈ for the Node.js community