Package Exports
- @nasriya/cachify
Readme
Cachify
Cachify is a fast, flexible caching library for Node.js supporting key-value and file caching with multi-storage and lifecycle management.
Visit us at www.nasriya.net.
Made with β€οΈ in Palestine π΅πΈ
Overview
Cachify is a fast, flexible caching library for Node.js that supports both key-value and file caching across multiple storage backends, with built-in lifecycle management and persistence.
This documentation covers the essential concepts, setup, and best practices to get started quickly and efficiently.
Contents
- Why Cachify and When to Use It
- Installation & Importing
- Importing
- Usage
- Testing
- Benchmarking
- License
[!IMPORTANT]
π Support Our Open-Source Development! π We need your support to keep our projects going! If you find our work valuable, please consider contributing. Your support helps us continue to develop and maintain these tools.
Every contribution, big or small, makes a difference. Thank you for your generosity and support!
Why Cachify and When to Use It
Cachify goes beyond traditional key-value caching like Redis, offering a unified, flexible, and highly extensible caching solution for Node.js.
Key Advantages
- Unified caching for keys and files: Cache key-value pairs and files in memory, Redis, or other backends seamlessly.
- Multi-storage support: Combine memory, Redis, and custom engines for redundancy, failover, and multi-region setups.
- Automated file lifecycle management: Automatic revalidation, eviction, and TTL handling.
- Persistence & cold-start recovery: Backup and restore your cache to survive application restarts without rebuilding.
- Extensibility: Easily plug in custom storage engines or adapters.
- Fastest read-first strategy: Queries multiple backends and returns the first successful result to optimize latency.
- Isolation: Multiple cache clients can coexist safely, even when sharing storage engines like Redis.
When to Use Cachify Instead of Just Redis
- You need file caching in memory or Redis, with automatic retrieval by file path.
- You want automatic file revalidation without writing extra watchers.
- Your application requires multi-storage redundancy or fastest-response reads across multiple backends.
- You need persistent caching that survives cold starts without rebuilding.
- You want a Node.js-native, highly extensible caching library that complements or goes beyond Redis.
Installation & Importing
Installation
npm install @nasriya/cachifyImporting
Importing in ESM modules
import cachify from '@nasriya/cachify';Importing in CommonJS modules
const cachify = require('@nasriya/cachify').default;Usage
This section guides you through Cachifyβs core usage in a logical order.
1. Creating Clients (Isolation)
The imported cachify object is an instance of the Cachify class,
which extends CachifyClient. It behaves like a cache client but also provides global utilities such as debugging, configuration, and client creation.
You can create isolated clients for independent caches β useful for multi-tenant systems, different environments, or testing.
import cachify from '@nasriya/cachify';
// Create an isolated instance
const isolated = cachify.createClient();
// Each instance maintains its own managers, engines, and configurations
await isolated.kvs.set('1', 'value');
await cachify.kvs.get('1'); // β undefined β isolated from the other instance
// Both share the same API surface, but only `cachify` includes utilities like:
console.log(cachify.debug); // Access global debug utilities
console.log(cachify.createClient); // Create new isolated clientsNotes:
- Isolated clients behave like
CachifyClientinstances but also include additional properties and methods fromCachify, such asdebugandcreateClient. - All usage patterns shown for the global
cachifyinstance apply to isolated clients. - Useful for multi-tenant systems, testing, or environments requiring independent caches.
2. Registering Storage Engines
Before storing or reading records in a backend like Redis, you must register your storage engines:
import { createClient } from '@redis/client';
// Create Redis clients
const redisEU = createClient({ url: process.env.REDIS_EU });
const redisUS = createClient({ url: process.env.REDIS_US });
// Register the clients with Cachify
cachify.engines.useRedis('redis-eu', redisEU);
cachify.engines.useRedis('redis-us', redisUS);
// Register a custom engine
cachify.engines.defineEngine('custom-engine', {
onSet: async (record, value, context) => {
context.set(record.key, value);
},
onRead: async (record, context): Promise<any> => {
return context.get(record.key);
},
onRemove: async (record, context): Promise<void> => {
if (context.has(record.key)) { context.delete(record.key) }
}
});Notes:
- Any backend (e.g., Redis) must be registered with Cachify before use.
- Names used in
storeInordefaultEnginesmust exactly match registered engine names. - Attempting to use an unregistered engine will throw an error at runtime.
- Redis integration is optional; Cachify defaults to in-memory storage if no backend is configured.
3. Default Storage Engines
You can set default engines for any record manager (kvs, files, etc.) to avoid specifying storeIn on every operation:
// For key-value records
cachify.kvs.defaultEngines = 'redis-eu';
// Or multiple engines
cachify.kvs.defaultEngines = ['redis-eu'];
// Redundant / multi-region setup
cachify.kvs.defaultEngines = ['redis-eu', 'redis-us'];
// For file records
cachify.files.defaultEngines = 'redis-eu';
cachify.files.defaultEngines = ['redis-eu', 'redis-us'];Notes:
- Operations without a
storeInoption automatically use the defineddefaultEngines. - Applies to all record managers (
kvs,files, and custom managers). - Multiple engines allow redundancy, failover, or multi-region caching.
- Engines must be registered before assigning them as defaults.
- Simplifies code and ensures consistent storage behavior across operations.
4. Caching (KVS & Files)
Key-Value Caching (KVS)
// Recommended: set a record in the "users" scope
await cachify.kvs.set('1', { name: 'Ahmad' }, { scope: 'users' });
// Retrieve from the same scope
const user = await cachify.kvs.get('1', 'users');
console.log(user); // { name: 'Ahmad' }
// Optional: store in multiple backends
await cachify.kvs.set('2', { name: 'Omar' }, { scope: 'users', storeIn: ['memory', 'redis-eu'] });
const user2 = await cachify.kvs.get('2', 'users');
console.log(user2); // { name: 'Omar' }
// Scopes are optional β default is "global"
await cachify.kvs.set('site', { name: 'Cachify' });
const site = await cachify.kvs.get('site');
console.log(site); // { name: 'Cachify' }File Caching
const filePath = 'path/to/file.txt';
// Cache a file in the "documents" scope
await cachify.files.set(filePath, { scope: 'documents' });
// Inspect file metadata
const fileRecord = cachify.files.inspect({ filePath, scope: 'documents' });
console.log(fileRecord);
// Read file content (status: "miss" if loaded from disk, "hit" if cached)
const readResult = await cachify.files.read({ filePath, scope: 'documents' });
console.log(readResult);
// Scopes are optional β caches in default "global" scope
await cachify.files.set(filePath);Notes:
- Scopes are optional; if omitted, the
"global"scope is used. - Scopes allow logical separation of data without polluting record keys (e.g.,
"users","orders","documents"). kvsis the plural API for key-value operations.- File caching separates metadata from content, which is loaded on read.
storeInallows targeting multiple backends for redundancy, failover, or multi-region caching.
5. Persistence & Cold Start Recovery
Cachify supports persistent caching via adapters (e.g., local, S3) to backup and restore caches:
import path from 'path';
const backupName = 'cars';
const testFilePath = path.join(process.cwd(), 'test', 'sample.txt');
// Register persistence adapters
cachify.persistence.use('local', { path: process.cwd() });
// Set some records
await cachify.kvs.set('a', 1);
await cachify.files.set(testFilePath);
// Backup cache
await cachify.persistence.backup('local', backupName);
// Clear memory
await cachify.clear();
// Restore cache
await cachify.persistence.restore('local', backupName);
// Access restored data
console.log(await cachify.kvs.get('a')); // 1
const fileResponse = await cachify.files.read({ filePath: testFilePath });
console.log(fileResponse); // { status: 'hit' | 'miss', content: Buffer }Notes:
- Backup saves all key-value and file caches to the configured persistence adapter.
- Restore reloads all cached data, enabling fast recovery after cold starts.
- Works with multiple cache flavors and storage backends.
- Cloud adapters (e.g., S3) can be registered similarly to local adapters for persistent storage.
Testing
To run Cachify tests locally, you need to create an environment file at tests/setup/test.env
Required Environment Variables
Redis Testing
REDIS_TEST_URLβ The URL of a Redis server for running tests.- β οΈ The Redis server will be flushed before tests start, so do not use a production Redis instance.
Amazon S3 Persistence Testing (Optional)
S3_TEST_BUCKETβ The bucket name to use for tests.S3_TEST_REGIONβ The AWS region of the bucket.S3_TEST_KEYβ AWS access key ID.S3_TEST_SECRETβ AWS secret access key.
Running Tests
After creating and populating the env file, simply run:
npm testBenchmarking
Cachify provides a built-in benchmarking suite to measure the performance of key-value and file caching across different storage engines.
Environment Setup
You can optionally create an environment file at benchmarks/benchmarks.env. This file allows you to customize benchmark parameters. If itβs missing, Cachify will automatically fall back to safe defaults.
Optional Environment Variables
BENCHMARK_KV_COUNTβ Number of key-value records to benchmark. Default:100000BENCHMARK_FILES_COUNTβ Number of file records to benchmark. Default:1000BENCHMARK_OUT_DIRβ Directory to store benchmark results. Default:${process.cwd()}/cachify/benchmarks-resultsREDIS_BENCHMARK_URLβ Redis connection URL to include Redis in the benchmarks.
If omitted, all benchmarks will run in-memory only.
[!WARNING] Redis Safety Notice
WhenREDIS_BENCHMARK_URLis defined, Cachify will flush the Redis database before starting the benchmarks to ensure accurate results.β οΈ Never use a production Redis server for benchmarking!
Use a dedicated or disposable Redis instance instead, as all data will be permanently deleted.
Running Benchmarks
Once ready, simply run:
npm run benchmarkThis command runs the full benchmark suite and outputs performance results β including read/write throughput and engine comparison β to the directory defined in BENCHMARK_OUT_DIR (or the default if not set).
License
This software is licensed under the Nasriya Personal & Commercial License (NPCL), version 1.0. Please read the license from here.