Redis
Port 6379 Cache, sessions, rate limits, pub/sub, queues.
Connection
REDIS_URL=redis://:PASSWORD@db.bizfylabs.com:6379
# App ACL user (recommended):
REDIS_URL=redis://myapp_user:PASSWORD@db.bizfylabs.com:6379
Key Naming
Prefix every key with your app name: myapp:category:id
myapp:session:abc123
myapp:cache:user:42
myapp:ratelimit:1.2.3.4
myapp:queue:emails
Setup
npm install redis
import { createClient } from 'redis';
const client = createClient({ url: process.env.REDIS_URL });
await client.connect();
CRUD — Strings
Used for: sessions, simple cache, counters, locks.
// CREATE / SET
await client.set('myapp:session:token', JSON.stringify({ userId: 42 }));
await client.set('myapp:cache:products', data, { EX: 300 }); // TTL 5 min
await client.set('myapp:lock:job1', '1', { NX: true, EX: 30 }); // distributed lock
// READ
const raw = await client.get('myapp:session:token');
const session = raw ? JSON.parse(raw) : null;
const exists = await client.exists('myapp:session:token');
// UPDATE (overwrite)
await client.set('myapp:session:token', JSON.stringify({ userId: 99 }));
// DELETE
await client.del('myapp:session:token');
await client.del(['myapp:key1', 'myapp:key2']); // multiple
CRUD — Hashes
Used for: structured objects (user profile, settings).
// CREATE
await client.hSet('myapp:user:42', {
name: 'Alice', email: 'a@b.com', lastLogin: new Date().toISOString()
});
// READ
const user = await client.hGetAll('myapp:user:42');
const name = await client.hGet('myapp:user:42', 'name');
// UPDATE
await client.hSet('myapp:user:42', 'name', 'Alice Updated');
await client.hIncrBy('myapp:user:42', 'loginCount', 1);
// DELETE field or whole hash
await client.hDel('myapp:user:42', 'lastLogin');
await client.del('myapp:user:42');
CRUD — Lists (Queues)
// CREATE (push)
await client.lPush('myapp:queue:emails', JSON.stringify({ to: 'a@b.com' }));
await client.rPush('myapp:queue:emails', JSON.stringify({ to: 'b@c.com' }));
// READ
const job = await client.rPop('myapp:queue:emails');
const peek = await client.lRange('myapp:queue:emails', 0, 9);
const len = await client.lLen('myapp:queue:emails');
// DELETE
await client.lRem('myapp:queue:emails', 1, job);
CRUD — Sets
// CREATE
await client.sAdd('myapp:online:users', '42', '99');
// READ
const members = await client.sMembers('myapp:online:users');
const isOnline = await client.sIsMember('myapp:online:users', '42');
// DELETE
await client.sRem('myapp:online:users', '42');
CRUD — Sorted Sets
// CREATE
await client.zAdd('myapp:leaderboard', { score: 1500, value: 'player1' });
// READ (top 10)
const top = await client.zRangeWithScores('myapp:leaderboard', 0, 9, { REV: true });
// UPDATE score
await client.zIncrBy('myapp:leaderboard', 50, 'player1');
// DELETE
await client.zRem('myapp:leaderboard', 'player1');
Scan Keys (safe alternative to KEYS *)
for await (const key of client.scanIterator({ MATCH: 'myapp:session:*', COUNT: 100 })) {
console.log(key);
}
Rate Limiting Pattern
async function checkRateLimit(userId) {
const key = `myapp:ratelimit:${userId}`;
const count = await client.incr(key);
if (count === 1) await client.expire(key, 60);
return count <= 100;
}
Admin — Create ACL User
Platform admin only. Users are scoped to key prefix
myapp:*.docker exec -it bizfy-redis redis-cli -a "$REDIS_PASSWORD"
# Read/write user — can only touch myapp:* keys
ACL SETUSER myapp_user on >strong-random-password ~myapp:* +@all -@dangerous
# Read-only user
ACL SETUSER myapp_readonly on >strong-random-password ~myapp:* +@read -@dangerous
# Verify
ACL LIST
ACL GETUSER myapp_user
# Delete user
ACL DELUSER myapp_user
ACL Command Reference
| Command | Meaning |
|---|---|
on | Enable the user |
>password | Set password |
~myapp:* | Only keys matching this pattern |
+@all -@dangerous | All commands except dangerous ones |
+@read | Read-only commands |
Send to Developer
REDIS_URL=redis://myapp_user:PASSWORD@db.bizfylabs.com:6379