Home / Code Samples

Redis vs Memcached: The Same Task, Side-by-Side

5 tasks with real code in Python/Node.js. Where Memcached cannot do it, the column says so. All code targets current versions: Redis 8.10, Memcached 1.6.x, Valkey 9.1 (commands shown work across the Redis 8.x and Valkey 9.x lines).

1. Cache GET/SET with TTL

Memcached (pymemcache)
from pymemcache.client import base

c = base.Client(('localhost', 11211))

# Set with 60-second TTL
c.set('page:home', '<html>...', expire=60)

# Get
value = c.get('page:home')

# Delete
c.delete('page:home')
Redis (redis-py)
import redis

r = redis.Redis(host='localhost', port=6379)

# Set with 60-second TTL
r.set('page:home', '<html>...', ex=60)

# Get
value = r.get('page:home')

# Delete
r.delete('page:home')
Valkey (redis-py)
import redis

# Valkey is RESP-compatible: same client
r = redis.Redis(host='valkey-host', port=6379)

# Identical API to Redis
r.set('page:home', '<html>...', ex=60)
value = r.get('page:home')
r.delete('page:home')

2. Atomic counter with TTL (rate limiter primitive)

Memcached, awkward
from pymemcache.client import base

c = base.Client(('localhost', 11211))

def rate_check(ip: str) -> bool:
    key = f"rl:{ip}"
    count = c.incr(key, 1)
    if count is None:
        # Race: two threads may both add on first hit
        c.add(key, 1, expire=60)
        return False
    # WARNING: TTL NOT updated on incr
    # You must track expiry separately
    return count > 100

Race condition on first hit. TTL not extended on incr. Fragile.

Redis / Valkey, atomic, correct
import redis, time

r = redis.Redis()

def rate_check(ip: str, limit=100, window=60) -> bool:
    key = f"rl:{ip}:{int(time.time()) // window}"
    count = r.incr(key)
    if count == 1:
        r.expire(key, window)  # Set TTL on first hit
    return count > limit

# INCR is atomic. Expire on first hit.
# No race conditions. No retry loops.
# Valkey: identical API.

Atomic INCR. TTL set on first hit. No race conditions.

3. Hash field with per-field TTL (Redis 8.0)

Memcached
Not supported. Memcached does not have hashes. Approximate with per-field keys + manual TTL management.
Redis 8.0 (HEXPIRE)
# Redis 8.0: per-field TTL on hash
HSET user:123 name "Ada" email "ada@x.com" auth_token "tok"

# auth_token expires in 15 minutes
HEXPIRE user:123 900 FIELDS 1 auth_token

# name and email persist (no expiry)
# Session: different fields, different lifetimes
Valkey 9.0
Hash field TTL (HEXPIRE / HPEXPIRE / HTTL) shipped in Valkey 9.0 (Oct 2025). Syntax matches Redis 8.0, so the Redis example on the left runs unchanged on Valkey 9.0+. On Valkey 8.1 and earlier, use whole-hash EXPIRE as a workaround.

4. Pub/sub fan-out

Memcached
Not supported. Memcached is a key-value cache only. For pub/sub, use Redis, Valkey, Kafka, or NATS.
Redis (ioredis, Node.js)
import Redis from 'ioredis';

const sub = new Redis();
const pub = new Redis();

sub.subscribe('chat:room1');

sub.on('message', (channel, msg) => {
  console.log(`[${channel}] ${msg}`);
});

pub.publish('chat:room1', JSON.stringify({
  user: 'ada',
  text: 'hello',
  ts: Date.now(),
}));
Valkey (ioredis, identical)
import Redis from 'ioredis';

// Valkey: same RESP protocol, same client
const sub = new Redis({ host: 'valkey-host' });
const pub = new Redis({ host: 'valkey-host' });

sub.subscribe('chat:room1');

sub.on('message', (channel, msg) => {
  console.log(`[${channel}] ${msg}`);
});

pub.publish('chat:room1', JSON.stringify({
  user: 'ada',
  text: 'hello',
  ts: Date.now(),
}));

5. Sorted-set leaderboard

Memcached
Not supported. Memcached has no sorted sets. Leaderboard requires application-side sorting: read all scores, sort in code, write back. O(N log N) in your app, not the cache.
Redis / Valkey (redis-py)
import redis

r = redis.Redis()

# Add / update scores, O(log N)
r.zadd('leaderboard', {
    'player1': 1500,
    'player2': 2200,
    'player3': 1800,
})

# Top 10, O(log N + 10)
top10 = r.zrevrange(
    'leaderboard', 0, 9, withscores=True
)
# [('player2', 2200.0), ('player3', 1800.0), ...]

# Player rank, O(log N)
rank = r.zrevrank('leaderboard', 'player1')
# 0-indexed: 2 (third place)

Valkey: identical API. Both support ZADD/ZREVRANGE/ZREVRANK.

Bonus: Redis 8.0 vector search
# Redis 8.0: vector similarity search (HNSW)
# Add embeddings (3D example)
VADD products VALUES 0.1 0.9 0.3 "product:101"
VADD products VALUES 0.8 0.2 0.6 "product:102"
VADD products VALUES 0.15 0.85 0.35 "product:103"

# Find top 2 similar to a query vector
VSIM products VALUES 0.12 0.88 0.32 COUNT 2
# -> "product:101", "product:103"

# Memcached: not supported
# Valkey: no VADD/VSIM core type; use the valkey-search module (GA Jul 2025) for vector similarity
Use case guides →Feature comparison →Valkey vs Redis →

Didn't find your answer?

Ask us. A real person reads every question and we answer the ones we can, with sources. If your question would help other readers, we may publish an anonymised version, with your permission. General reference only.

Ask a question

questions@redisvsmemcached.com