Redis Core Knowledge
SkillDatabases & dataRedis 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.
No other account needed.
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_docswith technology:redisfor 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
| Metric | Target |
|---|---|
| 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
postgresqlormysqlfor structured data with relationships - Document storage - Use
mongodbfor complex document structures - Full-text search - Use
elasticsearchfor 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-Pattern | Problem | Solution |
|---|---|---|
| No TTL on keys | Memory leak, unbounded growth | Always set expiration with SETEX or EXPIRE |
| Storing large objects | Performance degradation, memory pressure | Keep values small (<100KB), use compression |
| Using KEYS in production | Blocks server, O(N) operation | Use SCAN for iteration |
| No connection pooling | Connection exhaustion | Configure pool (ioredis, node-redis) |
| Ignoring eviction policy | Random data loss when full | Set appropriate policy (allkeys-lru) |
| Single Redis instance | Single point of failure | Use Redis Cluster or Sentinel |
| No password in production | Security vulnerability | Always configure AUTH |
Quick Troubleshooting
| Problem | Diagnostic | Fix |
|---|---|---|
| Memory full | INFO memory, MEMORY STATS | Increase maxmemory, set eviction policy |
| Slow responses | SLOWLOG GET 10 | Optimize queries, use pipelining |
| Connection refused | Check maxclients limit | Increase limit or fix connection leaks |
| High latency | redis-cli --latency | Check network, enable keep-alive |
| Keys not expiring | TTL key returns -1 | Set TTL on keys, check PERSIST calls |
| Replication lag | INFO replication | Check 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