memory-cache
GitHub Overview
dotnet/runtime
.NET is a cross-platform runtime for cloud, mobile, desktop, and IoT apps.
Topics
Star History
Library
memory-cache
Overview
memory-cache is a simple in-memory cache library for Node.js. It provides lightweight key-value storage through basic put/get/del methods, achieving fast data access with a minimal feature set. As of 2025, version 0.2.0 remains the latest version with its last update 8 years ago, yet it continues to be used by 730+ projects and serves as a reliable choice for simple caching needs. While adoption for new projects has declined due to the rise of modern alternatives, it maintains a solid track record of stable operation in existing projects.
Details
memory-cache 0.2.0 is a stable version released 8 years ago, providing simple cache implementation that serves as a foundation for the Node.js ecosystem. As a pure JavaScript library without external dependencies, it features minimal design with no TTL functionality, no statistics, and no event capabilities. It achieves high-speed operation through direct Object manipulation and minimizes learning costs with an easy-to-understand API. Currently, high-featured alternatives like node-cache, lru-cache, and cache-manager have become mainstream, requiring careful consideration for new projects.
Key Features
- Simple API: Intuitive operations through put(), get(), del()
- Lightweight Implementation: Minimal codebase without external dependencies
- Fast Access: High-speed data access through direct object manipulation
- Immediate Use: Ready to use without configuration
- Compatibility: Works with older Node.js versions
- Predictability: Predictable behavior due to lack of complex features
Pros and Cons
Pros
- Extremely simple and understandable API (minimal learning cost)
- Immediate use without external dependencies
- Lightweight and fast memory access (minimal overhead)
- Reliability through 8 years of stable operation track record
- High compatibility with older Node.js versions
- Easy debugging (simple internal structure)
Cons
- 8 years without updates (maintenance abandoned state)
- No TTL functionality (no expiration management)
- No statistics functionality (difficult monitoring/optimization)
- No event functionality (no cache state change monitoring)
- No memory leak protection (manual cleanup required)
- No modern TypeScript support
Reference Pages
Code Examples
Installation and Basic Setup
# NPM installation
npm install memory-cache
# Yarn installation
yarn add memory-cache
# TypeScript definitions not included (separate type definitions required)
npm install --save-dev @types/memory-cache
Basic Cache Operations
const cache = require('memory-cache')
// Basic put/get operations
cache.put('user:1', { name: 'John', age: 30 })
const user = cache.get('user:1')
console.log(user) // { name: 'John', age: 30 }
// Set data with TTL (milliseconds)
cache.put('session:abc123', 'session_data', 5 * 60 * 1000) // 5 minutes
// Get non-existent key
const notFound = cache.get('nonexistent')
console.log(notFound) // null
// Delete key
cache.del('user:1')
// Clear all data
cache.clear()
// Get current key list
const keys = cache.keys()
console.log('Cache keys:', keys)
// Get cache size
const size = cache.size()
console.log('Cache size:', size)
// Check key existence (custom implementation)
function hasKey(key) {
return cache.get(key) !== null
}
console.log('Has user:1:', hasKey('user:1'))
TTL Management and Cleanup System
const cache = require('memory-cache')
class TTLCacheWrapper {
constructor() {
this.cache = cache
this.cleanupInterval = null
this.setupCleanup()
}
// Setup periodic cleanup
setupCleanup() {
// Check for expired items every 5 minutes
this.cleanupInterval = setInterval(() => {
this.cleanup()
}, 5 * 60 * 1000)
}
// Cleanup expired items
cleanup() {
const keys = this.cache.keys()
let cleanedCount = 0
keys.forEach(key => {
// memory-cache automatically removes expired items,
// so existence check is sufficient
if (this.cache.get(key) === null) {
cleanedCount++
}
})
console.log(`Cleaned up ${cleanedCount} expired items`)
}
// Short-term cache (5 minutes)
putShort(key, value) {
return this.cache.put(key, value, 5 * 60 * 1000)
}
// Medium-term cache (30 minutes)
putMedium(key, value) {
return this.cache.put(key, value, 30 * 60 * 1000)
}
// Long-term cache (2 hours)
putLong(key, value) {
return this.cache.put(key, value, 2 * 60 * 60 * 1000)
}
// Permanent cache (no TTL)
putPermanent(key, value) {
return this.cache.put(key, value)
}
get(key) {
return this.cache.get(key)
}
del(key) {
return this.cache.del(key)
}
clear() {
return this.cache.clear()
}
// Custom statistics
getStats() {
const keys = this.cache.keys()
const validKeys = keys.filter(key => this.cache.get(key) !== null)
return {
totalKeys: keys.length,
validKeys: validKeys.length,
expiredKeys: keys.length - validKeys.length,
memoryUsage: process.memoryUsage().heapUsed
}
}
// Resource cleanup
destroy() {
if (this.cleanupInterval) {
clearInterval(this.cleanupInterval)
this.cleanupInterval = null
}
this.cache.clear()
}
}
// Usage example
const ttlCache = new TTLCacheWrapper()
// Set data with different TTLs
ttlCache.putShort('temp:calc', { result: 42 })
ttlCache.putMedium('user:session', { userId: 123, authenticated: true })
ttlCache.putLong('config:app', { theme: 'dark', language: 'en' })
ttlCache.putPermanent('constants:pi', 3.14159)
// Check statistics
setInterval(() => {
console.log('Cache Stats:', ttlCache.getStats())
}, 60000)
// Cleanup on application exit
process.on('SIGINT', () => {
ttlCache.destroy()
process.exit()
})
Express.js Integration
const express = require('express')
const cache = require('memory-cache')
const app = express()
// Cache middleware
function cacheMiddleware(duration = 5 * 60 * 1000) {
return (req, res, next) => {
const key = req.originalUrl || req.url
const cached = cache.get(key)
if (cached) {
console.log(`Cache HIT: ${key}`)
return res.json(cached)
}
console.log(`Cache MISS: ${key}`)
// Response capture
const originalJson = res.json
res.json = function(data) {
// Save response to cache
cache.put(key, data, duration)
console.log(`Cache SET: ${key} (TTL: ${duration}ms)`)
originalJson.call(this, data)
}
next()
}
}
// Conditional cache middleware
function conditionalCache(condition, duration = 5 * 60 * 1000) {
return (req, res, next) => {
if (condition && !condition(req)) {
return next()
}
return cacheMiddleware(duration)(req, res, next)
}
}
// API endpoints
app.get('/api/users',
cacheMiddleware(10 * 60 * 1000), // 10 minute cache
async (req, res) => {
// Simulate heavy processing
await new Promise(resolve => setTimeout(resolve, 1000))
const users = [
{ id: 1, name: 'John', email: '[email protected]' },
{ id: 2, name: 'Jane', email: '[email protected]' }
]
res.json(users)
}
)
// User-specific data cache
app.get('/api/user/:id',
conditionalCache(
req => req.params.id && !isNaN(req.params.id),
15 * 60 * 1000 // 15 minute cache
),
async (req, res) => {
const userId = req.params.id
// Simulate database access
await new Promise(resolve => setTimeout(resolve, 500))
const user = {
id: parseInt(userId),
name: `User ${userId}`,
email: `user${userId}@example.com`,
lastAccess: new Date()
}
res.json(user)
}
)
// Cache statistics endpoint
app.get('/cache/stats', (req, res) => {
const keys = cache.keys()
const validKeys = keys.filter(key => cache.get(key) !== null)
res.json({
totalKeys: keys.length,
validKeys: validKeys.length,
expiredKeys: keys.length - validKeys.length,
keys: validKeys.slice(0, 10), // Show only first 10 keys
memoryUsage: process.memoryUsage()
})
})
// Cache clear endpoint
app.delete('/cache/:pattern?', (req, res) => {
const pattern = req.params.pattern
if (pattern) {
// Partial deletion with pattern matching
const keys = cache.keys()
const matchedKeys = keys.filter(key => key.includes(pattern))
matchedKeys.forEach(key => cache.del(key))
res.json({
message: `Cache cleared for pattern: ${pattern}`,
clearedKeys: matchedKeys.length,
clearedItems: matchedKeys
})
} else {
// Clear all cache
const beforeKeys = cache.keys().length
cache.clear()
res.json({
message: 'All cache cleared',
clearedKeys: beforeKeys
})
}
})
app.listen(3000, () => {
console.log('Server running on port 3000')
// Periodic cache monitoring
setInterval(() => {
const keys = cache.keys()
console.log(`Cache status - Total keys: ${keys.length}`)
}, 60000)
})
Backup and Restore Functionality
const cache = require('memory-cache')
const fs = require('fs')
const path = require('path')
class BackupCacheManager {
constructor() {
this.cache = cache
this.backupFile = path.join(__dirname, 'cache-backup.json')
this.autoBackupInterval = null
}
// Backup cache data
backup() {
try {
const keys = this.cache.keys()
const backupData = {
timestamp: Date.now(),
data: {}
}
keys.forEach(key => {
const value = this.cache.get(key)
if (value !== null) {
backupData.data[key] = value
}
})
fs.writeFileSync(this.backupFile, JSON.stringify(backupData, null, 2))
console.log(`Cache backup completed: ${keys.length} items saved`)
return {
success: true,
itemCount: Object.keys(backupData.data).length,
file: this.backupFile
}
} catch (error) {
console.error('Backup failed:', error)
return { success: false, error: error.message }
}
}
// Restore cache data
restore() {
try {
if (!fs.existsSync(this.backupFile)) {
throw new Error('Backup file not found')
}
const backupContent = fs.readFileSync(this.backupFile, 'utf8')
const backupData = JSON.parse(backupContent)
// Clear existing cache
this.cache.clear()
// Restore backup data
let restoredCount = 0
Object.entries(backupData.data).forEach(([key, value]) => {
this.cache.put(key, value)
restoredCount++
})
console.log(`Cache restore completed: ${restoredCount} items restored`)
return {
success: true,
itemCount: restoredCount,
backupTimestamp: backupData.timestamp
}
} catch (error) {
console.error('Restore failed:', error)
return { success: false, error: error.message }
}
}
// Enable automatic backup
enableAutoBackup(intervalMinutes = 30) {
if (this.autoBackupInterval) {
clearInterval(this.autoBackupInterval)
}
this.autoBackupInterval = setInterval(() => {
console.log('Performing automatic backup...')
this.backup()
}, intervalMinutes * 60 * 1000)
console.log(`Auto backup enabled: every ${intervalMinutes} minutes`)
}
// Disable automatic backup
disableAutoBackup() {
if (this.autoBackupInterval) {
clearInterval(this.autoBackupInterval)
this.autoBackupInterval = null
console.log('Auto backup disabled')
}
}
// Export cache to JSON format
exportToJSON(filePath) {
try {
const keys = this.cache.keys()
const exportData = {
exportDate: new Date().toISOString(),
totalItems: keys.length,
items: {}
}
keys.forEach(key => {
const value = this.cache.get(key)
if (value !== null) {
exportData.items[key] = {
value: value,
type: typeof value,
exportedAt: Date.now()
}
}
})
fs.writeFileSync(filePath, JSON.stringify(exportData, null, 2))
return {
success: true,
itemCount: Object.keys(exportData.items).length,
file: filePath
}
} catch (error) {
return { success: false, error: error.message }
}
}
// Import cache from JSON format
importFromJSON(filePath) {
try {
const importContent = fs.readFileSync(filePath, 'utf8')
const importData = JSON.parse(importContent)
let importedCount = 0
Object.entries(importData.items || {}).forEach(([key, item]) => {
this.cache.put(key, item.value)
importedCount++
})
return {
success: true,
itemCount: importedCount,
originalExportDate: importData.exportDate
}
} catch (error) {
return { success: false, error: error.message }
}
}
// Resource cleanup
destroy() {
this.disableAutoBackup()
}
}
// Usage example
const backupManager = new BackupCacheManager()
// Set data
cache.put('user:1', { name: 'John', email: '[email protected]' })
cache.put('config:app', { theme: 'dark', version: '1.0' })
cache.put('session:abc', { userId: 1, loginTime: Date.now() })
// Backup and restore
const backupResult = backupManager.backup()
console.log('Backup result:', backupResult)
// Enable automatic backup (every 10 minutes)
backupManager.enableAutoBackup(10)
// Test export functionality
const exportResult = backupManager.exportToJSON('./cache-export.json')
console.log('Export result:', exportResult)
// Cleanup on process exit
process.on('SIGINT', () => {
backupManager.backup() // Final backup
backupManager.destroy()
process.exit()
})
Migration Support to Modern Libraries
const memoryCache = require('memory-cache')
/**
* Migration helper from memory-cache to node-cache
*/
class MigrationHelper {
constructor() {
this.oldCache = memoryCache
this.migrationLog = []
}
// Prepare data migration
prepareMigration() {
const keys = this.oldCache.keys()
const migrationData = []
keys.forEach(key => {
const value = this.oldCache.get(key)
if (value !== null) {
migrationData.push({
key,
value,
type: typeof value,
migrationTime: Date.now()
})
}
})
console.log(`Migration preparation completed: ${migrationData.length} items ready`)
return migrationData
}
// Convert to node-cache format
convertToNodeCache(migrationData) {
const NodeCache = require('node-cache')
const newCache = new NodeCache({ stdTTL: 600, checkperiod: 120 })
migrationData.forEach(item => {
newCache.set(item.key, item.value)
this.migrationLog.push({
action: 'migrated',
key: item.key,
timestamp: Date.now()
})
})
console.log(`Migration to node-cache completed: ${migrationData.length} items`)
return newCache
}
// Convert to lru-cache format
convertToLRUCache(migrationData) {
const { LRUCache } = require('lru-cache')
const newCache = new LRUCache({ max: 500, ttl: 1000 * 60 * 10 })
migrationData.forEach(item => {
newCache.set(item.key, item.value)
this.migrationLog.push({
action: 'migrated',
key: item.key,
timestamp: Date.now()
})
})
console.log(`Migration to lru-cache completed: ${migrationData.length} items`)
return newCache
}
// Get migration log
getMigrationLog() {
return this.migrationLog
}
// Compatibility layer (recommended for temporary use only)
createCompatibilityLayer(newCache) {
return {
put: (key, value, ttl) => {
if (ttl) {
return newCache.set(key, value, ttl)
}
return newCache.set(key, value)
},
get: (key) => {
const value = newCache.get(key)
return value !== undefined ? value : null
},
del: (key) => {
return newCache.delete ? newCache.delete(key) : newCache.del(key)
},
clear: () => {
return newCache.clear ? newCache.clear() : newCache.flushAll()
},
keys: () => {
return newCache.keys ? newCache.keys() : []
},
size: () => {
return newCache.size || newCache.getStats().keys
}
}
}
}
// Migration example
const migrationHelper = new MigrationHelper()
// Prepare existing data
memoryCache.put('user:1', { name: 'John' })
memoryCache.put('config:app', { theme: 'dark' })
// Execute migration
const migrationData = migrationHelper.prepareMigration()
const newNodeCache = migrationHelper.convertToNodeCache(migrationData)
// Temporary use with compatibility layer
const compatCache = migrationHelper.createCompatibilityLayer(newNodeCache)
// Existing code works as-is
console.log(compatCache.get('user:1')) // { name: 'John' }
console.log(compatCache.size()) // 2
console.log('Migration log:', migrationHelper.getMigrationLog())
Enhanced Type Definitions for TypeScript
// Type-safe usage in TypeScript environment
declare module 'memory-cache' {
interface CacheStatic {
put<T>(key: string, value: T, time?: number): T
get<T>(key: string): T | null
del(key: string): boolean
clear(): void
size(): number
keys(): string[]
}
const cache: CacheStatic
export = cache
}
// Usage example
import cache = require('memory-cache')
interface User {
id: number
name: string
email: string
}
interface CacheWrapper {
setUser(userId: number, user: User): User
getUser(userId: number): User | null
deleteUser(userId: number): boolean
getAllUsers(): User[]
}
class TypedMemoryCache implements CacheWrapper {
setUser(userId: number, user: User): User {
return cache.put<User>(`user:${userId}`, user, 30 * 60 * 1000) // 30 minutes
}
getUser(userId: number): User | null {
return cache.get<User>(`user:${userId}`)
}
deleteUser(userId: number): boolean {
return cache.del(`user:${userId}`)
}
getAllUsers(): User[] {
const keys = cache.keys()
return keys
.filter(key => key.startsWith('user:'))
.map(key => cache.get<User>(key))
.filter((user): user is User => user !== null)
}
getStats() {
return {
totalKeys: cache.size(),
keys: cache.keys()
}
}
}
// Usage example
const typedCache = new TypedMemoryCache()
const user: User = {
id: 1,
name: 'John Doe',
email: '[email protected]'
}
typedCache.setUser(1, user)
const cachedUser = typedCache.getUser(1) // Type is User | null