A modern, multi-layered caching library for TypeScript with built-in stampede protection and a modular adapter ecosystem.
- Multi-layer caching — Stack fast local caches (memory) with shared distributed caches (Redis). Reads cascade through layers; cache misses automatically backfill higher layers.
- Stampede protection — Concurrent cache misses for the same key coalesce into a single factory call. 100 simultaneous requests = 1 database query.
- Modular adapters — Bring your own storage backend. Ships with in-memory, Redis, Memcached, and SQLite adapters. Implement the
CacheAdapterinterface to add more. - Batch operations —
mget,mset,mdelfor efficient multi-key operations with multi-layer orchestration and automatic backfill. - NestJS integration — First-class
@Cached()decorator andZigguratModulefor dependency injection. Zero boilerplate caching on any service method. - Fully typed — Generic
CacheEntry<T>ensures type safety from cache to consumer. Noanycasts needed. - Observable — Built-in event system for hit/miss rates, per-layer latency, backfill, and stampede coalescing. Optional
@ziggurat-cache/otelpackage for OpenTelemetry integration. - Resilient — Individual layer failures are silently skipped. A Redis outage won't take down your application.
| Package | Description |
|---|---|
@ziggurat-cache/core |
CacheManager, MemoryAdapter, BaseCacheAdapter, and all core types |
@ziggurat-cache/redis |
Redis adapter using ioredis |
@ziggurat-cache/memcache |
Memcached adapter using memjs |
@ziggurat-cache/sqlite |
SQLite adapter using better-sqlite3 for persistent local caching |
@ziggurat-cache/nestjs |
NestJS module and @Cached() decorator |
@ziggurat-cache/otel |
OpenTelemetry instrumentation (counters, histograms) |
# Core package (includes MemoryAdapter)
npm install @ziggurat-cache/core
# Optional: Redis adapter
npm install @ziggurat-cache/redis ioredis
# Optional: Memcached adapter
npm install @ziggurat-cache/memcache memjs
# Optional: SQLite adapter (persistent local cache)
npm install @ziggurat-cache/sqlite better-sqlite3
# Optional: NestJS integration
npm install @ziggurat-cache/nestjs
# Optional: OpenTelemetry instrumentation
npm install @ziggurat-cache/otel @opentelemetry/apiimport { CacheManager, MemoryAdapter } from "@ziggurat-cache/core";
const cache = new CacheManager({
namespace: "users",
layers: [new MemoryAdapter({ defaultTtlMs: 300_000 })],
});
// wrap: fetch from cache or compute and cache
// Key is stored as "users:profile:42"
const user = await cache.wrap(`profile:${userId}`, async () =>
db.users.findById(userId),
);Each adapter manages its own TTL — memory expires fast, Redis holds data longer:
import { CacheManager, MemoryAdapter } from "@ziggurat-cache/core";
import { RedisAdapter } from "@ziggurat-cache/redis";
import Redis from "ioredis";
const cache = new CacheManager({
namespace: "products",
layers: [
new MemoryAdapter({ defaultTtlMs: 30_000 }), // L1: 30s TTL
new RedisAdapter({ client: new Redis(), defaultTtlMs: 600_000 }), // L2: 10min TTL
],
});
// L1 miss → L2 hit → value returned + L1 backfilled with L1's own TTL
const product = await cache.wrap(id, async () => api.getProduct(id));// app.module.ts
import { Module } from "@nestjs/common";
import { ZigguratModule } from "@ziggurat-cache/nestjs";
import { MemoryAdapter } from "@ziggurat-cache/core";
@Module({
imports: [
ZigguratModule.forRoot({
layers: [new MemoryAdapter()],
}),
],
})
export class AppModule {}
// user.service.ts
import { Injectable } from "@nestjs/common";
import { Cached } from "@ziggurat-cache/nestjs";
@Injectable()
export class UserService {
@Cached({
key: (id: string) => `user:profile:${id}`,
ttlMs: 300_000,
})
async getUserProfile(id: string) {
return this.db.users.findById(id);
}
}See the docs directory for detailed guides:
- Getting Started — Installation, first cache, and core concepts
- Core Concepts — Layers, backfill, stampede protection explained
- API Reference — Complete API for all packages
- Custom Adapters — How to build your own
CacheAdapter - Redis Adapter — Configuration, serialization, and production tips
- Memcache Adapter — Memcached configuration and limitations
- SQLite Adapter — Persistent local caching with SQLite
- NestJS Integration — Module setup, decorators, and async configuration
- Advanced Usage — Error handling, performance tuning, observability, and patterns
- Node.js >= 18
- TypeScript >= 5.x (recommended)
# Clone and install
git clone https://github.com/camcima/ziggurat.git
cd ziggurat
pnpm install
# Build all packages
pnpm build
# Run tests
pnpm test
# Lint and format
pnpm lint
pnpm format:checkContributions are welcome! Please:
- Fork the repository
- Create a feature branch (
git checkout -b feature/my-feature) - Write tests for your changes
- Ensure
pnpm test && pnpm lintpasses - Submit a pull request
If you maintain a fork or related repository, consider adding these topics for discoverability:
cache, caching, multi-layer-cache, stampede-protection, dogpile-prevention, typescript, nodejs, redis, memcached, sqlite
MIT