All Articles
Tech News9 min read

Redis Caching Strategies for High-Performance Applications

Learn when and how to use Redis effectively. Caching patterns, cache invalidation, and real-world implementation examples.

T

TechGyanic

December 3, 2025

Redis Caching Strategies for High-Performance Applications

Our API response times dropped from 800ms to 50ms after implementing Redis properly. Here's the complete guide to caching that actually works.

Why Redis?

  • In-memory storage - Microsecond latency
  • Rich data structures - Not just key-value
  • Persistence options - Don't lose data on restart
  • Pub/Sub - Real-time messaging

Basic Operations

const Redis = require('ioredis');
const redis = new Redis(process.env.REDIS_URL);

// Set and Get
await redis.set('user:123', JSON.stringify(userData));
await redis.set('session:abc', 'data', 'EX', 3600); // Expires in 1 hour

const user = JSON.parse(await redis.get('user:123'));

// Delete
await redis.del('user:123');

// Check existence
const exists = await redis.exists('user:123');

Caching Patterns

Cache-Aside (Lazy Loading)

Most common pattern:

async function getUser(userId) {
  const cacheKey = `user:${userId}`;
  
  // Check cache first
  const cached = await redis.get(cacheKey);
  if (cached) {
    return JSON.parse(cached);
  }
  
  // Cache miss - fetch from DB
  const user = await db.users.findUnique({ where: { id: userId } });
  
  // Store in cache with 1-hour TTL
  await redis.set(cacheKey, JSON.stringify(user), 'EX', 3600);
  
  return user;
}

Write-Through

Update cache when writing to database:

async function updateUser(userId, data) {
  // Update database
  const user = await db.users.update({
    where: { id: userId },
    data
  });
  
  // Update cache immediately
  await redis.set(`user:${userId}`, JSON.stringify(user), 'EX', 3600);
  
  return user;
}

Cache Invalidation

async function deleteUser(userId) {
  await db.users.delete({ where: { id: userId } });
  
  // Invalidate related caches
  await redis.del(`user:${userId}`);
  await redis.del(`user:${userId}:posts`);
  await redis.del(`user:${userId}:followers`);
}

Advanced Data Structures

Hash (for objects)

// Store user as hash (more memory efficient)
await redis.hset('user:123', {
  name: 'Priya',
  email: '[email protected]',
  role: 'admin'
});

// Get single field
const name = await redis.hget('user:123', 'name');

// Get all fields
const user = await redis.hgetall('user:123');

Sorted Set (for leaderboards)

// Add scores
await redis.zadd('leaderboard', 1000, 'player:1');
await redis.zadd('leaderboard', 1500, 'player:2');

// Get top 10
const topPlayers = await redis.zrevrange('leaderboard', 0, 9, 'WITHSCORES');

// Get player rank
const rank = await redis.zrevrank('leaderboard', 'player:1');

List (for queues)

// Add to queue
await redis.lpush('email:queue', JSON.stringify(emailData));

// Process from queue
const email = JSON.parse(await redis.rpop('email:queue'));

Cache Warming

Pre-populate cache for known hot data:

async function warmCache() {
  const popularProducts = await db.products.findMany({
    where: { featured: true }
  });
  
  const pipeline = redis.pipeline();
  
  popularProducts.forEach(product => {
    pipeline.set(`product:${product.id}`, JSON.stringify(product), 'EX', 7200);
  });
  
  await pipeline.exec();
}

Avoiding Cache Stampede

When cache expires, prevent all requests from hitting DB:

async function getWithLock(key, fetchFn, ttl = 3600) {
  const cached = await redis.get(key);
  if (cached) return JSON.parse(cached);
  
  const lockKey = `lock:${key}`;
  const acquired = await redis.set(lockKey, '1', 'NX', 'EX', 10);
  
  if (!acquired) {
    // Another process is fetching, wait and retry
    await new Promise(r => setTimeout(r, 100));
    return getWithLock(key, fetchFn, ttl);
  }
  
  try {
    const data = await fetchFn();
    await redis.set(key, JSON.stringify(data), 'EX', ttl);
    return data;
  } finally {
    await redis.del(lockKey);
  }
}

Monitoring

Key metrics to watch:

  • Hit rate (should be > 95%)
  • Memory usage
  • Connection count
  • Latency

Redis is simple to start with but has depth. Master these patterns and your applications will fly.

rediscachingperformancebackenddatabase
Share this article
T

Written by

TechGyanic

Sharing insights on technology, software architecture, and development best practices.