Skip to main content

5-Minute Quickstart

Get up and running with Cachemate in under 5 minutes.

src/cache.ts
import { Client, type TableRegistry } from 'cachemate';

// 1. Define table tags and version keys
const registry: TableRegistry = {
entries: {
users: { tag: 'u', versionKey: 'cm:ver:users' },
orders: { tag: 'o', versionKey: 'cm:ver:orders' },
products: { tag: 'p', versionKey: 'cm:ver:products' },
},
alias: {
userProfiles: 'users',
},
};

// 2. Initialize the Cachemate client
export const cachemate = new Client({
memoryMaxMb: 128, // Required in TS: In-memory fallback LRU size
redisUrls: [
process.env.REDIS_PRIMARY_URL ?? 'redis://localhost:6379',
process.env.REDIS_REPLICA_URL ?? 'redis://localhost:6380',
],
registry,
appName: 'ecommerce-api',
defaultTtl: 120, // 2 minutes
});

// 3. Cache a complex multi-table query
interface OrderSummary {
orderId: string;
total: number;
customerName: string;
}

export async function getOrderSummary(orderId: string): Promise<OrderSummary> {
return await cachemate.cache<OrderSummary>({
tables: ['orders', 'users'],
filters: { orderId },
ttlSeconds: 300,
loader: async () => {
// Executed ONLY on cache miss
console.log(`[DB] Fetching order summary from PostgreSQL for ${orderId}`);
return await db.query(
'SELECT o.id, o.total, u.name as customerName FROM orders o JOIN users u ON o.user_id = u.id WHERE o.id = $1',
[orderId]
);
},
});
}

// 4. Invalidate whenever a table changes
export async function updateOrder(orderId: string, data: any): Promise<void> {
await db.update('orders', orderId, data);
// Bumps version counter in Redis. All dependent order queries invalidate instantly!
await cachemate.invalidate('orders');
}

How It Works Under the Hood

  1. Deterministic Key Generation: When you call client.cache(), Cachemate reads the current versions of all requested tables (ver:users and ver:posts) using mget().
  2. Composite Key: It hashes your filters object with SHA-1 and constructs a key: cm:p-u:1:4:a3f9e1b2c4d5.
  3. Instant Invalidation: When you call client.invalidate('posts'), the Redis counter ver:posts increments from 4 to 5.
  4. No Stale Data: The next lookup for userId automatically asks for cm:p-u:1:5:a3f9e1b2c4d5. The old key ...:1:4:... is simply ignored and cleaned up by Redis TTL automatically.