Skip to main content
Technology & EngineeringCaching Services166 lines

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.

Quick Summary27 lines
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 lines
Paste into your CLAUDE.md or agent config

Memcached 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

Get CLI access →

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.

Caching Services167L

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.

Caching Services197L

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.

Caching Services165L

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.

Caching Services206L

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.

Caching Services167L

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.

Caching Services207L