JSPM

  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 308
  • Score
    100M100P100Q83003F
  • License NPCL-1

A lightweight, extensible in-memory caching library for storing anything, with built-in TTL and customizable cache types.

Package Exports

  • @nasriya/cachify

Readme

Cachify Logo

Cachify

Cachify is a fast, flexible caching library for Node.js supporting key-value and file caching with multi-storage and lifecycle management.

NPM License NPM Version NPM Unpacked Size Last Commit Status

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

[!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.

Click here to support us!

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/cachify

Importing

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 clients

Notes:

  • Isolated clients behave like CachifyClient instances but also include additional properties and methods from Cachify, such as debug and createClient.
  • All usage patterns shown for the global cachify instance 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 storeIn or defaultEngines must 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 storeIn option automatically use the defined defaultEngines.
  • 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").
  • kvs is the plural API for key-value operations.
  • File caching separates metadata from content, which is loaded on read.
  • storeIn allows 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 test

Benchmarking

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: 100000
  • BENCHMARK_FILES_COUNT β€” Number of file records to benchmark. Default: 1000
  • BENCHMARK_OUT_DIR β€” Directory to store benchmark results. Default: ${process.cwd()}/cachify/benchmarks-results
  • REDIS_BENCHMARK_URL β€” Redis connection URL to include Redis in the benchmarks.
    If omitted, all benchmarks will run in-memory only.

[!WARNING] Redis Safety Notice
When REDIS_BENCHMARK_URL is 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 benchmark

This 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.