Implement effective caching strategies with Redis for high-performance applications
# Redis Caching Patterns
Master caching strategies with Redis using Google Antigravity IDE. This comprehensive guide covers cache patterns, data structures, and production optimization.
## Why Redis Caching?
Redis provides in-memory data storage with persistence options. Google Antigravity IDE's Gemini 3 engine suggests optimal caching strategies for your use case.
## Connection Setup
```typescript
// lib/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,
maxRetriesPerRequest: 3,
retryDelayOnFailover: 100,
enableReadyCheck: true,
lazyConnect: true,
});
redis.on("error", (error) => {
console.error("Redis connection error:", error);
});
redis.on("connect", () => {
console.log("Connected to Redis");
});
export { redis };
```
## Cache-Aside Pattern
```typescript
// services/userService.ts
import { redis } from "@/lib/redis";
import { db } from "@/lib/db";
const USER_CACHE_TTL = 3600; // 1 hour
export async function getUser(userId: string): Promise<User | null> {
const cacheKey = `user:${userId}`;
// Try cache first
const cached = await redis.get(cacheKey);
if (cached) {
return JSON.parse(cached);
}
// Fetch from database
const user = await db.user.findUnique({
where: { id: userId },
});
if (user) {
// Store in cache
await redis.setex(cacheKey, USER_CACHE_TTL, JSON.stringify(user));
}
return user;
}
export async function updateUser(userId: string, data: UpdateUserData): Promise<User> {
const user = await db.user.update({
where: { id: userId },
data,
});
// Invalidate cache
await redis.del(`user:${userId}`);
return user;
}
export async function deleteUser(userId: string): Promise<void> {
await db.user.delete({ where: { id: userId } });
// Invalidate all related caches
const keys = await redis.keys(`user:${userId}:*`);
if (keys.length > 0) {
await redis.del(...keys);
}
await redis.del(`user:${userId}`);
}
```
## Write-Through Pattern
```typescript
// services/sessionService.ts
export async function createSession(userId: string): Promise<Session> {
const session: Session = {
id: generateId(),
userId,
createdAt: Date.now(),
expiresAt: Date.now() + SESSION_TTL * 1000,
};
// Write to cache and database simultaneously
await Promise.all([
redis.setex(
`session:${session.id}`,
SESSION_TTL,
JSON.stringify(session)
),
db.session.create({ data: session }),
]);
return session;
}
export async function getSession(sessionId: string): Promise<Session | null> {
const cached = await redis.get(`session:${sessionId}`);
if (cached) {
return JSON.parse(cached);
}
// Fallback to database
const session = await db.session.findUnique({
where: { id: sessionId },
});
if (session && session.expiresAt > Date.now()) {
// Re-populate cache
const ttl = Math.floor((session.expiresAt - Date.now()) / 1000);
await redis.setex(`session:${sessionId}`, ttl, JSON.stringify(session));
return session;
}
return null;
}
```
## Rate Limiting
```typescript
// middleware/rateLimit.ts
export async function checkRateLimit(
key: string,
limit: number,
window: number
): Promise<{ allowed: boolean; remaining: number; resetAt: number }> {
const now = Date.now();
const windowKey = `ratelimit:${key}:${Math.floor(now / (window * 1000))}`;
const multi = redis.multi();
multi.incr(windowKey);
multi.pttl(windowKey);
const [[, count], [, ttl]] = await multi.exec();
if (ttl === -1) {
await redis.pexpire(windowKey, window * 1000);
}
const remaining = Math.max(0, limit - (count as number));
const resetAt = now + (ttl > 0 ? ttl : window * 1000);
return {
allowed: (count as number) <= limit,
remaining,
resetAt,
};
}
```
## Leaderboard with Sorted Sets
```typescript
// services/leaderboardService.ts
export async function updateScore(userId: string, score: number): Promise<void> {
await redis.zadd("leaderboard:global", score, userId);
}
export async function getLeaderboard(start = 0, end = 9): Promise<LeaderboardEntry[]> {
const results = await redis.zrevrange(
"leaderboard:global",
start,
end,
"WITHSCORES"
);
const entries: LeaderboardEntry[] = [];
for (let i = 0; i < results.length; i += 2) {
entries.push({
userId: results[i],
score: parseFloat(results[i + 1]),
rank: start + i / 2 + 1,
});
}
return entries;
}
export async function getUserRank(userId: string): Promise<number | null> {
const rank = await redis.zrevrank("leaderboard:global", userId);
return rank !== null ? rank + 1 : null;
}
```
## Pub/Sub for Real-Time Updates
```typescript
// services/pubsub.ts
const subscriber = redis.duplicate();
export async function subscribe(channel: string, callback: (message: string) => void): Promise<void> {
await subscriber.subscribe(channel);
subscriber.on("message", (ch, message) => {
if (ch === channel) {
callback(message);
}
});
}
export async function publish(channel: string, message: object): Promise<void> {
await redis.publish(channel, JSON.stringify(message));
}
```
## Best Practices
- Use appropriate cache TTLs for data freshness
- Implement cache invalidation strategies
- Apply rate limiting to protect resources
- Use sorted sets for leaderboards
- Leverage pub/sub for real-time features
- Monitor cache hit rates
Google Antigravity IDE provides Redis caching patterns and automatically suggests optimal data structures for your caching needs.This Redis prompt is ideal for developers working on:
By using this prompt, you can save hours of manual coding and ensure best practices are followed from the start. It's particularly valuable for teams looking to maintain consistency across their redis implementations.
Yes! All prompts on Antigravity AI Directory are free to use for both personal and commercial projects. No attribution required, though it's always appreciated.
This prompt works excellently with Claude, ChatGPT, Cursor, GitHub Copilot, and other modern AI coding assistants. For best results, use models with large context windows.
You can modify the prompt by adding specific requirements, constraints, or preferences. For Redis projects, consider mentioning your framework version, coding style, and any specific libraries you're using.