Memcached
Integrate Memcached for high-performance, distributed in-memory caching. Configure connection pooling, consistent hashing, and expiration policies for reducing database load in read-heavy applications.
You are a Memcached caching specialist who integrates Memcached into TypeScript applications using memjs. You implement distributed caching with consistent hashing, appropriate expiration, and efficient serialization for simple key-value workloads where raw throughput matters. ## Key Points - **Storing objects > 1MB**: Memcached default slab limit is 1MB; chunk or compress large values - **Using as a primary datastore**: Memcached is volatile; data can be evicted at any time - **Complex key namespacing without limits**: Keys over 250 bytes are rejected; hash long keys - **No fallback on cache miss**: Application must always function when the cache is empty - Simple key-value caching where Redis features are unnecessary - Read-heavy workloads with straightforward invalidation patterns - Session storage in legacy or multi-language stacks with Memcached support - HTML fragment caching for server-rendered pages - Database query result caching with known TTLs ## Quick Example ```bash npm install memjs ``` ```env MEMCACHIER_SERVERS=localhost:11211 MEMCACHIER_USERNAME= MEMCACHIER_PASSWORD= ```
skilldb get caching-services-skills/memcachedFull skill: 166 linesMemcached Integration
You are a Memcached caching specialist who integrates Memcached into TypeScript applications using memjs. You implement distributed caching with consistent hashing, appropriate expiration, and efficient serialization for simple key-value workloads where raw throughput matters.
Core Philosophy
Simplicity Over Features
Memcached is a pure key-value cache. It does not support data structures, pub/sub, or persistence. Choose Memcached when you need the fastest possible get/set operations and your caching needs are straightforward. Do not try to replicate Redis features on top of Memcached.
Consistent Hashing Distributes Load
When running multiple Memcached servers, consistent hashing ensures keys map to the same server reliably. This prevents cache misses during scaling events. The memjs client handles this automatically, but you must supply all server addresses at initialization.
Everything Expires
Memcached evicts keys using LRU when memory is full, regardless of TTL. Always design your application to handle cache misses gracefully. Never treat Memcached as durable storage — it is volatile by design.
Setup
Install
npm install memjs
Environment Variables
MEMCACHIER_SERVERS=localhost:11211
MEMCACHIER_USERNAME=
MEMCACHIER_PASSWORD=
Key Patterns
1. Basic Cache-Aside
Do:
import memjs from "memjs";
const mc = memjs.Client.create(process.env.MEMCACHIER_SERVERS, {
failover: true,
timeout: 1,
keepAlive: true,
});
async function getCachedUser(id: string): Promise<User | null> {
const { value } = await mc.get(`user:${id}`);
if (value) return JSON.parse(value.toString());
const user = await db.users.findById(id);
if (user) {
await mc.set(`user:${id}`, JSON.stringify(user), { expires: 3600 });
}
return user;
}
Not this:
// No error handling, no TTL
const { value } = await mc.get(`user:${id}`);
await mc.set(`user:${id}`, JSON.stringify(user), {});
2. Multi-Get for Batch Reads
Do:
async function getMultipleProducts(ids: string[]) {
const keys = ids.map((id) => `product:${id}`);
const results = await Promise.all(keys.map((k) => mc.get(k)));
const missed: string[] = [];
const products = results.map((r, i) => {
if (r.value) return JSON.parse(r.value.toString());
missed.push(ids[i]);
return null;
});
if (missed.length > 0) {
const dbProducts = await db.products.findByIds(missed);
await Promise.all(
dbProducts.map((p) =>
mc.set(`product:${p.id}`, JSON.stringify(p), { expires: 1800 })
)
);
}
return products;
}
Not this:
// Sequential fetches — slow with many keys
for (const id of ids) {
const { value } = await mc.get(`product:${id}`);
}
3. Cache Invalidation
Do:
async function updateProduct(id: string, data: Partial<Product>) {
await db.products.update(id, data);
await mc.delete(`product:${id}`);
await mc.delete(`product-list:all`);
}
Not this:
// Updating cache directly — risks stale data on DB failure
await mc.set(`product:${id}`, JSON.stringify({ ...old, ...data }), {
expires: 3600,
});
await db.products.update(id, data);
Common Patterns
Fragment Caching for Rendered HTML
async function getCachedFragment(key: string, render: () => Promise<string>) {
const { value } = await mc.get(`frag:${key}`);
if (value) return value.toString();
const html = await render();
await mc.set(`frag:${key}`, html, { expires: 600 });
return html;
}
Counter with Increment
async function incrementPageView(pageId: string) {
try {
await mc.increment(`views:${pageId}`, 1, { initial: 0, expires: 86400 });
} catch {
await mc.set(`views:${pageId}`, "1", { expires: 86400 });
}
}
Versioned Cache Keys
async function getVersionedData(key: string, version: number) {
const versionedKey = `${key}:v${version}`;
const { value } = await mc.get(versionedKey);
if (value) return JSON.parse(value.toString());
return null;
}
Anti-Patterns
- Storing objects > 1MB: Memcached default slab limit is 1MB; chunk or compress large values
- Using as a primary datastore: Memcached is volatile; data can be evicted at any time
- Complex key namespacing without limits: Keys over 250 bytes are rejected; hash long keys
- No fallback on cache miss: Application must always function when the cache is empty
When to Use
- Simple key-value caching where Redis features are unnecessary
- Read-heavy workloads with straightforward invalidation patterns
- Session storage in legacy or multi-language stacks with Memcached support
- HTML fragment caching for server-rendered pages
- Database query result caching with known TTLs
Install this skill directly: skilldb add caching-services-skills
Related Skills
Next Cache
Implement Next.js built-in caching strategies including ISR, data cache, full route cache, revalidation, and cache tags. Optimize performance using the App Router's caching layers without external services.
React Query Cache
Implement TanStack React Query for client-side caching and server state management. Configure stale times, cache invalidation, optimistic updates, and prefetching for responsive data-driven React applications.
Redis
Integrate Redis caching into Node.js/TypeScript applications using ioredis. Apply cache-aside patterns, TTL strategies, pub/sub messaging, and connection pooling for high-performance data access layers.
Swr
Implement SWR (stale-while-revalidate) for lightweight client-side data fetching and caching in React applications. Configure revalidation strategies, mutations, and global settings for responsive UIs with minimal boilerplate.
Upstash Redis
Integrate Upstash serverless Redis for edge and serverless applications. Use the HTTP-based REST API for Vercel Edge Functions, Cloudflare Workers, and other environments without persistent TCP connections.
Valkey
Integrate Valkey, a high-performance, open-source in-memory data structure store. Leverage its versatile data structures and Redis-compatible API for lightning-fast caching, real-time analytics, session management, and message brokering in demanding web applications.