Redis Core Knowledge

SkillDatabases & data

Redis in-memory data store. Covers data structures, caching, and pub/sub. Use for caching and real-time features.

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the Redis Core Knowledge skill

What this skill tells your AI

The instructions your AI receives, as published by claude-dev-suite/claude-dev-suite in skills/databases/redis/SKILL.md and read by ahel’s review.

Deep Knowledge: Use mcp__documentation__fetch_docs with technology: redis for comprehensive documentation.

Data Types

Strings

SET user:1:name "John"
GET user:1:name
SETEX session:abc 3600 "user_data"  # Expires in 1h
INCR page:views

Hashes

HSET user:1 name "John" email "john@example.com"
HGET user:1 name
HGETALL user:1
HINCRBY user:1 loginCount 1

Lists

LPUSH notifications:1 "New message"
RPUSH queue:jobs '{"task": "send_email"}'
LRANGE notifications:1 0 9
LPOP queue:jobs

Sets

SADD user:1:roles "admin" "editor"
SISMEMBER user:1:roles "admin"
SMEMBERS user:1:roles
SINTER user:1:friends user:2:friends  # Common friends

Sorted Sets

ZADD leaderboard 100 "user:1" 200 "user:2"
ZRANGE leaderboard 0 9 REV WITHSCORES  # Top 10
ZINCRBY leaderboard 10 "user:1"

Common Patterns

Caching

async function getUser(id) {
  const cached = await redis.get(`user:${id}`);
  if (cached) return JSON.parse(cached);

  const user = await db.users.find(id);
  await redis.setex(`user:${id}`, 3600, JSON.stringify(user));
  return user;
}

Rate Limiting

async function rateLimit(ip) {
  const key = `ratelimit:${ip}`;
  const count = await redis.incr(key);
  if (count === 1) await redis.expire(key, 60);
  return count <= 100;
}

Production Readiness

Connection Configuration

// redis.ts
import Redis from 'ioredis';

const redis = new Redis({
  host: process.env.REDIS_HOST,
  port: parseInt(process.env.REDIS_PORT || '6379'),
  password: process.env.REDIS_PASSWORD,
  db: parseInt(process.env.REDIS_DB || '0'),

  // Connection pool
  maxRetriesPerRequest: 3,
  retryStrategy: (times) => {
    if (times > 10) return null; // Stop retrying
    return Math.min(times * 100, 3000);
  },

  // TLS for production
  tls: process.env.NODE_ENV === 'production' ? {} : undefined,

  // Keep-alive
  keepAlive: 30000,
  connectTimeout: 10000,
});

redis.on('error', (err) => {
  console.error('Redis connection error:', err);
});

redis.on('connect', () => {
  console.log('Redis connected');
});

export { redis };

Cache Patterns

// Generalized cache-aside pattern
async function cacheAside<T>(
  key: string,
  ttl: number,
  fetcher: () => Promise<T>
): Promise<T> {
  const cached = await redis.get(key);
  if (cached) {
    return JSON.parse(cached);
  }

  const data = await fetcher();
  await redis.setex(key, ttl, JSON.stringify(data));
  return data;
}

// Cache invalidation
async function invalidatePattern(pattern: string): Promise<void> {
  const keys = await redis.keys(pattern);
  if (keys.length > 0) {
    await redis.del(...keys);
  }
}

// Example usage
const user = await cacheAside(
  `user:${id}`,
  3600, // 1 hour TTL
  () => db.users.findUnique({ where: { id } })
);

// On user update
await invalidatePattern(`user:${id}*`);

Rate Limiting (Sliding Window)

async function slidingWindowRateLimit(
  key: string,
  limit: number,
  windowSeconds: number
): Promise<{ allowed: boolean; remaining: number }> {
  const now = Date.now();
  const windowStart = now - windowSeconds * 1000;

  const multi = redis.multi();
  multi.zremrangebyscore(key, 0, windowStart);
  multi.zadd(key, now, `${now}-${Math.random()}`);
  multi.zcard(key);
  multi.expire(key, windowSeconds);

  const results = await multi.exec();
  const count = results?.[2]?.[1] as number;

  return {
    allowed: count <= limit,
    remaining: Math.max(0, limit - count),
  };
}

Session Storage

interface SessionData {
  userId: string;
  roles: string[];
  createdAt: number;
}

async function createSession(userId: string, roles: string[]): Promise<string> {
  const sessionId = crypto.randomUUID();
  const session: SessionData = {
    userId,
    roles,
    createdAt: Date.now(),
  };

  await redis.setex(
    `session:${sessionId}`,
    86400, // 24 hours
    JSON.stringify(session)
  );

  return sessionId;
}

async function getSession(sessionId: string): Promise<SessionData | null> {
  const data = await redis.get(`session:${sessionId}`);
  return data ? JSON.parse(data) : null;
}

async function deleteSession(sessionId: string): Promise<void> {
  await redis.del(`session:${sessionId}`);
}

Distributed Locking

async function acquireLock(
  resource: string,
  ttlMs: number
): Promise<string | null> {
  const lockId = crypto.randomUUID();
  const result = await redis.set(
    `lock:${resource}`,
    lockId,
    'PX',
    ttlMs,
    'NX'
  );
  return result === 'OK' ? lockId : null;
}

async function releaseLock(resource: string, lockId: string): Promise<boolean> {
  const script = `
    if redis.call("get", KEYS[1]) == ARGV[1] then
      return redis.call("del", KEYS[1])
    else
      return 0
    end
  `;
  const result = await redis.eval(script, 1, `lock:${resource}`, lockId);
  return result === 1;
}

Monitoring

// Health check
async function healthCheck(): Promise<{ status: string; latency: number }> {
  const start = Date.now();
  await redis.ping();
  return {
    status: 'healthy',
    latency: Date.now() - start,
  };
}

// Key metrics
async function getMetrics() {
  const info = await redis.info('stats');
  const memory = await redis.info('memory');
  return { info, memory };
}

Monitoring Metrics

MetricTarget
Connection pool usage< 80%
Cache hit ratio> 90%
Latency (p99)< 5ms
Memory usage< 80% max

Checklist

  • Connection pooling configured
  • TLS enabled in production
  • Retry strategy with backoff
  • Password authentication
  • Key expiration on all cached data
  • Cache invalidation strategy
  • Rate limiting implemented
  • Distributed locking for critical sections
  • Health check endpoint
  • Memory monitoring alerts

When NOT to Use This Skill

  • Relational data - Use postgresql or mysql for structured data with relationships
  • Document storage - Use mongodb for complex document structures
  • Full-text search - Use elasticsearch for search indexing and analytics
  • Primary database - Redis is for caching/sessions, not as main data store
  • Large objects - Store references in Redis, data in object storage

Anti-Patterns

Anti-PatternProblemSolution
No TTL on keysMemory leak, unbounded growthAlways set expiration with SETEX or EXPIRE
Storing large objectsPerformance degradation, memory pressureKeep values small (<100KB), use compression
Using KEYS in productionBlocks server, O(N) operationUse SCAN for iteration
No connection poolingConnection exhaustionConfigure pool (ioredis, node-redis)
Ignoring eviction policyRandom data loss when fullSet appropriate policy (allkeys-lru)
Single Redis instanceSingle point of failureUse Redis Cluster or Sentinel
No password in productionSecurity vulnerabilityAlways configure AUTH

Quick Troubleshooting

ProblemDiagnosticFix
Memory fullINFO memory, MEMORY STATSIncrease maxmemory, set eviction policy
Slow responsesSLOWLOG GET 10Optimize queries, use pipelining
Connection refusedCheck maxclients limitIncrease limit or fix connection leaks
High latencyredis-cli --latencyCheck network, enable keep-alive
Keys not expiringTTL key returns -1Set TTL on keys, check PERSIST calls
Replication lagINFO replicationCheck network, reduce write load

Reference Documentation

Signals

GitHub stars
33
Forks
6
Last commit
Sep 2026

ahel review

  • S4info
    community integration — published by claude-dev-suite, not redis

Automated review, not a security audit. Ruleset v1.

Advanced
Catalog kind
skill
Gateway key
redis-claude-dev-suite
Source
github.com/claude-dev-suite/claude-dev-suite