PureTools

Redis Data Types: When to Use Each One

PureTools Team· 8 min read
Redis Data Types: When to Use Each One

Redis: More Than a Cache

Redis is an in-memory data structure store. Most people use it as a cache, but its data types enable session storage, real-time leaderboards, rate limiting, pub/sub messaging, and job queues — all with sub-millisecond latency.

Data Types Overview

TypeUse CaseExample
StringCache, counters, sessionsPage cache, rate limit counter
HashObject storageUser profile, product details
ListQueues, activity feedsJob queue, recent messages
SetUnique collections, tagsOnline users, unique visitors
Sorted SetRankings, time-seriesLeaderboard, priority queue
StreamEvent log, message queueActivity log, event sourcing

Strings

# Basic key-value
SET user:session:abc123 "{\"userId\": 42, \"role\": \"admin\"}"
GET user:session:abc123

# With expiration (TTL)
SET cache:page:/home "<html>...</html>" EX 3600  # expires in 1 hour

# Atomic counter
INCR api:rate:user:42      # increment by 1
INCRBY api:rate:user:42 5  # increment by 5
DECR api:rate:user:42      # decrement by 1

# Set only if not exists (distributed lock)
SET lock:order:123 "worker-1" NX EX 30  # NX = only if not exists

Hashes (Objects)

# Store object fields individually
HSET user:42 name "Alice" email "alice@example.com" role "admin"
HGET user:42 name          # "Alice"
HGETALL user:42            # all fields and values
HINCRBY user:42 login_count 1  # atomic field increment

# Better than storing JSON strings — update single fields without parsing

Lists (Queues)

# Job queue
LPUSH queue:emails "{\"to\": \"user@example.com\", \"subject\": \"Welcome\"}"
RPOP queue:emails          # pop from the right (FIFO)
BRPOP queue:emails 30      # blocking pop (wait up to 30s for new item)

# Recent activity (keep last 100)
LPUSH activity:user:42 "Logged in"
LTRIM activity:user:42 0 99  # keep only last 100 entries
LRANGE activity:user:42 0 9  # get last 10

Sets (Unique Collections)

# Track online users
SADD online:users "user:42" "user:17" "user:88"
SISMEMBER online:users "user:42"  # true
SCARD online:users                 # count: 3
SMEMBERS online:users              # all members

# Set operations
SINTER tag:javascript tag:react    # users who know both
SUNION tag:javascript tag:python   # users who know either
SDIFF  tag:javascript tag:react    # JS devs who don't know React

Sorted Sets (Rankings)

# Leaderboard
ZADD leaderboard 1500 "player:alice"
ZADD leaderboard 2200 "player:bob"
ZADD leaderboard 1800 "player:charlie"

ZRANK leaderboard "player:bob"        # rank (0-based)
ZREVRANGE leaderboard 0 9 WITHSCORES  # top 10
ZINCRBY leaderboard 100 "player:alice" # add 100 points

# Rate limiting with sliding window
ZADD rate:user:42 1682345678 "req:1"
ZRANGEBYSCORE rate:user:42 (now-60) +inf  # requests in last 60s

Common Patterns

# Node.js with ioredis
import Redis from 'ioredis';
const redis = new Redis(process.env.REDIS_URL);

// Cache with fallback
async function getCached(key, fetchFn, ttl = 3600) {
  const cached = await redis.get(key);
  if (cached) return JSON.parse(cached);
  
  const data = await fetchFn();
  await redis.set(key, JSON.stringify(data), 'EX', ttl);
  return data;
}

// Distributed lock
async function withLock(key, fn, ttl = 30) {
  const acquired = await redis.set(`lock:${key}`, '1', 'NX', 'EX', ttl);
  if (!acquired) throw new Error('Lock not acquired');
  try {
    return await fn();
  } finally {
    await redis.del(`lock:${key}`);
  }
}

Format your data: JSON Formatter — format Redis JSON values for readability.