Skip to content
Warlock.js v4

Introduction

@warlock.js/cache is a standalone Node.js caching library. It turns slow, repeated work — database queries, API calls, heavy computations — into cheap memory reads.

// Before: every request hits the database (~50ms each)
app.get("/product/:id", async (req, res) => {
const product = await db.products.findById(req.params.id);
res.json(product);
});
// After: the first request hits the database, the next 999 don't (~1ms each)
app.get("/product/:id", async (req, res) => {
const product = await cache.remember(
`products.${req.params.id}`,
"1h",
() => db.products.findById(req.params.id),
);
res.json(product);
});

What’s in the box:

  • 8 interchangeable drivers — Redis, Memory, Memory Extended, LRU, File, Null, Postgres (with optional pgvector), and Mock for tests.
  • Rich set optionsttl / expiresAt / tags / onConflict / per-call driver / vector for similarity.
  • Atomic operationsincrement, decrement, update, merge, conditional writes.
  • Cache tags — group related entries and invalidate them together.
  • List sub-API — queues, stacks, recent-N buffers.
  • Similarity retrieval — store embeddings alongside entries, query by meaning (what’s similarity?).
  • Stampede prevention — when 1000 concurrent requests all miss the same key, only one hits the source of truth (what’s a stampede?).
  • Stale-while-revalidate — return cached data instantly while a background refresh runs, so slow upstreams never make fast endpoints slow (SWR guide).
  • Event system — observe every cache operation.
  • Built-in metricscache.metrics() returns hit rate, latency percentiles, per-driver breakdowns (metrics guide).

:::info Standalone Package Works independently of the Warlock framework in any Node.js environment — Express, Fastify, NestJS, Next.js, Remix, or any other runtime that runs on Node.js. :::

:::tip TypeScript or JavaScript Examples use TypeScript. If you’re on plain JS, just drop the <Type> generics — everything works identically at runtime. :::

Terminal window
npm install @warlock.js/cache
MethodDescription
set(key, value, ttlOrOptions?)Store a value with optional TTL or rich options
get(key)Retrieve a cached value
remove(key)Delete a cache entry
has(key)Check if a key exists
pull(key)Get a value and delete it
forever(key, value)Store a value without expiration
remember(key, ttl, callback)Get cached value or compute and cache it (with stampede prevention)
flush()Clear all cache entries
increment(key, amount)Atomically increment a numeric value
decrement(key, amount)Atomically decrement a numeric value
update(key, fn)Atomic read-modify-write for objects
merge(key, partial)Shallow-merge a partial into a cached object
list<T>(key)Typed list accessor (push/shift/slice/trim)
many(keys)Retrieve multiple values at once
setMany(entries, ttl?)Store multiple values at once
removeNamespace(namespace)Delete all keys matching a namespace pattern

Conditional writes — “set only if missing” or “set only if present” — are expressed via set(k, v, { onConflict: "create" \| "update" }) and work across every driver (Redis-native, others emulated).

Use CaseRecommended Driver
Production, multi-server, distributedRedis
Local development, simple persistenceFile
Fastest, ephemeral, single-processMemory
Need sliding expirationMemory Extended
Limited memory, want LRU evictionLRU Memory
Testing, disable cacheNull
  • Set Options — rich third-arg object: ttl, expiresAt, tags, onConflict, per-call driver
  • Update & Merge — atomic read-modify-write for structured values
  • Cache Lists — queue / stack / recent-N buffer sub-API
  • Cache Tags — group related entries and invalidate them together
  • Atomic Operations — increment, decrement, and conditional writes without race conditions
  • Stampede Preventionremember() shares one concurrent regeneration per key
  • Events — observe every cache operation with 9 event types
  • Errors — error classes and how to react
import { cache, RedisCacheDriver } from "@warlock.js/cache";
cache.setCacheConfigurations({
default: "redis",
drivers: { redis: RedisCacheDriver },
options: { redis: { url: process.env.REDIS_URL, globalPrefix: "shop" } },
});
await cache.init();
// Cache a product for 1 hour (human-readable duration string)
const product = await cache.remember(
`products.${productId}`,
"1h",
() => db.products.findById(productId),
);
// Invalidate all cached orders for a user after checkout
await cache.removeNamespace(`orders.${userId}`);