Intermediate
25 mins

Caching Strategies

Learn how to implement effective caching strategies at different levels of your application stack to improve performance and reduce server load.

Prerequisites

  • Understanding of HTTP caching headers
  • Basic knowledge of CDNs
  • Familiarity with Redis or similar caching systems
  • Experience with Node.js middleware

Caching Overview

Caching Workflow

Visual representation of multi-layer caching strategy in a web application.

1

Browser Caching

Configure browser caching with proper cache headers:

// Set cache-control headers
app.use((req, res, next) => {
  // Static assets
  if (req.url.match(/.(jpg|jpeg|png|gif|css|js)$/)) {
    res.setHeader('Cache-Control', 'public, max-age=31536000');
  } else {
    // Dynamic content
    res.setHeader('Cache-Control', 'no-cache');
  }
  next();
});
2

CDN Caching

Implement CDN caching for static assets:

// Configure CDN caching rules
module.exports = {
  cdn: {
    // Cache static assets for 1 year
    '/static/*': {
      edge_ttl: 31536000,
      browser_ttl: 31536000,
      cache_by_default: true
    },
    // Cache API responses for 1 hour
    '/api/*': {
      edge_ttl: 3600,
      browser_ttl: 0,
      cache_by_default: false,
      cache_keys: ['cookie', 'host']
    }
  }
}
3

Application Caching

Set up in-memory caching for application data:

import NodeCache from 'node-cache';

// Initialize cache with TTL of 10 minutes
const cache = new NodeCache({ stdTTL: 600 });

// Cache middleware
const cacheMiddleware = (duration) => {
  return (req, res, next) => {
    const key = req.originalUrl;
    const cachedResponse = cache.get(key);

    if (cachedResponse) {
      res.send(cachedResponse);
      return;
    }

    res.sendResponse = res.send;
    res.send = (body) => {
      cache.set(key, body, duration);
      res.sendResponse(body);
    };
    next();
  };
};

// Apply to routes
app.get('/api/data', cacheMiddleware(300), (req, res) => {
  // Route handler
});
4

Database Caching

Implement database query caching:

import Redis from 'ioredis';

const redis = new Redis();

async function getCachedData(key, fetchFn) {
  // Try to get from cache
  const cached = await redis.get(key);
  if (cached) {
    return JSON.parse(cached);
  }

  // Fetch fresh data
  const data = await fetchFn();
  
  // Cache for 1 hour
  await redis.setex(key, 3600, JSON.stringify(data));
  
  return data;
}

// Usage example
const users = await getCachedData('users', async () => {
  return await db.users.findAll();
});

Best Practices

Cache Invalidation

Strategies for effective cache invalidation:

  • Use versioned cache keys
  • Implement cache busting
  • Set appropriate TTLs
  • Monitor cache hit rates

Performance Optimization

Optimize caching for performance:

  • Cache at multiple levels
  • Use compression
  • Implement cache warming
  • Monitor memory usage

Security Considerations

Secure your caching implementation:

  • Don't cache sensitive data
  • Validate cached data
  • Use HTTPS for CDN
  • Implement access controls

Troubleshooting

Cache Invalidation Issues

Common caching problems:

  • Stale cache data
  • Cache key conflicts
  • Memory leaks
  • Race conditions

Performance Problems

Performance-related issues:

  • Low cache hit rates
  • Slow cache responses
  • Cache stampede
  • Memory pressure

Next Steps

Now that you understand caching strategies, explore these related topics: