Node.js Caching with Redis — Complete Guide to Performance Optimization
In this tutorial, you will learn about Node.js Caching with Redis. We cover key concepts, practical examples, and best practices to help you master this topic.
Redis is an in-memory data structure store used for caching, session management, Rate Limiting, and real-time data in Node.js applications for high-performance data access.
What You'll Learn
By the end of this tutorial, you'll connect to Redis from Node.js, implement caching strategies with TTL, handle cache invalidation, cache database queries, store sessions, and implement rate limiting.
Why Redis Caching Matters
Database queries are slow (milliseconds). Redis reads data from memory (microseconds). Caching frequently accessed data reduces database load, lowers latency, and improves user experience.
Real-World Use
An e-commerce API caches product listings in Redis. The first request fetches from PostgreSQL (50ms) and caches it. Subsequent requests read from Redis (1ms). Cache invalidates when a product is updated.
Redis Caching Learning Path
flowchart LR
A[File Upload] --> B[Caching Redis]
B --> C[Docker]
C --> D[Deployment]
D --> E[DevOps]
A --> F{You Are Here}
style F fill:#f90,color:#fff
Redis Connection
npm install redis
import { createClient } from "redis";
const redis = createClient({ url: process.env.REDIS_URL || "redis://localhost:6379" });
redis.on("error", (err) => console.error("Redis error:", err));
await redis.connect();
console.log("Redis connected");
Basic Caching
async function getCachedOrFetch(key, fetchFn, ttlSeconds = 3600) {
const cached = await redis.get(key);
if (cached) return JSON.parse(cached);
const data = await fetchFn();
await redis.setEx(key, ttlSeconds, JSON.stringify(data));
return data;
}
// Usage
app.get("/api/products", async (req, res) => {
const products = await getCachedOrFetch("products:all", () => db.products.findAll(), 300);
res.json(products);
});
Cache Invalidation
app.post("/api/products", async (req, res) => {
const product = await db.products.create(req.body);
await redis.del("products:all"); // Invalidate cache
res.status(201).json(product);
});
app.put("/api/products/:id", async (req, res) => {
const product = await db.products.update(req.params.id, req.body);
await redis.del("products:all");
await redis.del(`product:${req.params.id}`);
res.json(product);
});
Session Storage
import { RedisStore } from "connect-redis";
app.use(session({
store: new RedisStore({ client: redis }),
secret: process.env.SESSION_SECRET,
resave: false,
saveUninitialized: false,
cookie: { secure: true, httpOnly: true, maxAge: 86400000 }
}));
Rate Limiting with Redis
async function rateLimit(ip, maxRequests, windowSeconds) {
const key = `rate:${ip}`;
const current = await redis.incr(key);
if (current === 1) await redis.expire(key, windowSeconds);
return current <= maxRequests;
}
app.use(async (req, res, next) => {
const allowed = await rateLimit(req.ip, 100, 60);
if (!allowed) return res.status(429).json({ error: "Too many requests" });
next();
});
Caching Patterns
// Cache-aside pattern
async function getUser(id) {
const key = `user:${id}`;
let user = await redis.get(key);
if (user) return JSON.parse(user);
user = await db.users.findById(id);
if (user) await redis.setEx(key, 3600, JSON.stringify(user));
return user;
}
// Write-through pattern
async function updateUser(id, data) {
const user = await db.users.update(id, data);
await redis.setEx(`user:${id}`, 3600, JSON.stringify(user));
return user;
}
Common Mistakes
1. Caching Everything
Cache only frequently accessed, rarely changing data. Caching rarely accessed data wastes memory without performance benefit.
2. No Cache Invalidation Strategy
Stale data is worse than slow data. Always invalidate or update cache when underlying data changes.
3. Caching User-Specific Data Without Keys
If two users share the same cache key, they see each other's data. Include user ID in cache keys for personalized data.
4. Not Setting TTL
Without TTL (time-to-live), stale data lives forever. Always set reasonable expiration times.
5. Ignoring Cache Miss Storms
When cached data expires and many requests hit the database simultaneously, it creates a thundering herd. Use mutex locks for regeneration.
Practice Questions
1. Why is Redis faster than a database?
Redis stores everything in RAM (microsecond access). Databases store data on disk (millisecond access). Redis also has simpler data structures.
2. What is TTL in caching?
Time-to-Live: how long a cached entry stays valid. After TTL expires, the entry is automatically deleted, forcing a fresh fetch.
3. How do you invalidate a Redis cache?
Use redis.del(key) to remove specific keys, redis.flushDb() for full invalidation, or pattern-based deletion with SCAN + DEL.
4. What is the cache-aside pattern?
Application checks cache first. On miss, fetches from database, stores in cache, returns data. On update, invalidates cache.
5. Challenge: Implement a caching layer for a product API with automatic cache invalidation on updates.
app.get("/api/products", async (req, res) => {
const cached = await redis.get("products");
if (cached) return res.json(JSON.parse(cached));
const products = await db.products.findAll();
await redis.setEx("products", 300, JSON.stringify(products));
res.json(products);
});
app.post("/api/products", async (req, res) => {
const product = await db.products.create(req.body);
await redis.del("products");
res.status(201).json(product);
});
FAQ
Mini Project: Caching Proxy
Build a caching proxy server that caches external API responses in Redis.
import express from "express";
import { createClient } from "redis";
const app = express();
const redis = createClient();
await redis.connect();
app.get("/proxy/*", async (req, res) => {
const apiUrl = req.params[0];
const cacheKey = `proxy:${apiUrl}`;
const cached = await redis.get(cacheKey);
if (cached) return res.json(JSON.parse(cached));
const response = await fetch(apiUrl);
const data = await response.json();
await redis.setEx(cacheKey, 300, JSON.stringify(data));
res.json(data);
});
app.listen(3000);
What's Next
Node.js Docker Node.js Deployment Express Security
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro