Redis
Connecting Node to Redis: official redis client vs ioredis, pooling, pub/sub, streams, and the patterns for caches + queues.
Node — Redis
EXAMPLE
# Install: npm install redis (official) or npm install ioredis
import { createClient } from 'redis';
# ===== Connect =====
const client = createClient({
url: process.env.REDIS_URL, # redis://user:pass@host:port/db
socket: { reconnectStrategy: (retries) => Math.min(retries * 50, 2000) },
});
client.on('error', (e) => console.error('redis', e));
await client.connect();
# ===== Basic ops =====
await client.set('user:1', 'Alex');
await client.set('user:1', 'Alex', { EX: 3600 }); # TTL 1h
const v = await client.get('user:1');
await client.del('user:1');
# Hashes:
await client.hSet('user:1', { name: 'Alex', email: 'a@x.io' });
const u = await client.hGetAll('user:1');
# Lists:
await client.lPush('queue', JSON.stringify({ id: 1 }));
const job = await client.lPop('queue');
# Sets / Sorted sets:
await client.sAdd('tags', 'vip');
await client.zAdd('leaderboard', { score: 100, value: 'alice' });
# ===== Pub/Sub =====
const sub = client.duplicate();
await sub.connect();
await sub.subscribe('chan', (message, channel) => {
console.log(channel, message);
});
await client.publish('chan', 'hello');
# ===== Streams =====
await client.xAdd('events', '*', { type: 'login', user: 'alex' });
const messages = await client.xRead([{ key: 'events', id: '0' }], { COUNT: 10 });
# ===== ioredis (alternative) =====
# npm install ioredis
import Redis from 'ioredis';
const redis = new Redis(process.env.REDIS_URL);
await redis.set('foo', 'bar');
await redis.get('foo');
# ioredis is widely used; supports cluster, sentinel, pipelining.
# ===== Cache pattern =====
async function getUser(id) {
const cached = await client.get(\`user:${id}\`);
if (cached) return JSON.parse(cached);
const user = await db.users.findById(id);
await client.set(\`user:${id}\`, JSON.stringify(user), { EX: 600 });
return user;
}
# Cache invalidation:
async function updateUser(id, data) {
await db.users.update(id, data);
await client.del(\`user:${id}\`);
}
# ===== Rate limit =====
async function tryRequest(ip) {
const key = \`rl:${ip}\`;
const count = await client.incr(key);
if (count === 1) await client.expire(key, 60);
if (count > 100) throw new Error('rate limit');
}
# ===== BullMQ for job queues =====
# npm install bullmq
import { Queue, Worker } from 'bullmq';
const queue = new Queue('emails', { connection: { host: 'localhost', port: 6379 } });
await queue.add('send', { to: 'a@x.io', subject: 'hi' });
const worker = new Worker('emails', async (job) => {
await sendEmail(job.data);
}, { connection: { host: 'localhost', port: 6379 } });
# ===== Patterns =====
# - One client per process; duplicate for sub
# - TTL on every cache key
# - JSON.stringify around objects (Redis strings)
# - BullMQ over custom queue logic
# ===== Pitfalls =====
# - Forgetting reconnectStrategy -> hard failures on transient blips
# - Storing big objects (>1MB) per key
# - Pub/Sub on a cluster (subscriptions are per-node)
# - Missing TTL -> memory growth
Why it matters
Node + Redis: official client or ioredis, one connection per process, TTL on caches, BullMQ for queues, pub/sub via duplicated client. The patterns are small; the discipline is set-TTL and avoid storing big values.
Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.
Example
Example
import { createClient } from 'redis';
const redis = await createClient().connect();
await redis.set('hits', 1);
await redis.incr('hits');
Try it Yourself »
Discussion
Loading…