Redis is an in-memory database. It is fast — reads and writes take microseconds. It is used for caching, sessions, rate limiting, pub/sub, queues, and leaderboards.

Redis 8.0 (released May 2025) includes JSON, vector search, probabilistic data structures, and time series natively — no extensions needed.

Setup with Docker

docker run -d \
  --name redis \
  -p 6379:6379 \
  redis:8 \
  redis-server --save 60 1 --loglevel warning

Connect with redis-cli:

redis-cli
# or with Docker:
docker exec -it redis redis-cli

Strings

The most basic type. Strings can hold text, numbers, or binary data (up to 512 MB).

SET user:1:name "Alex Johnson"
GET user:1:name
# "Alex Johnson"

# Set with expiration (seconds)
SET session:abc123 "user_data" EX 3600
TTL session:abc123
# 3600

# Atomic increment
SET page:home:views 0
INCR page:home:views
INCRBY page:home:views 5
GET page:home:views
# "6"

Lists

Ordered lists of strings. Push from either end — useful for queues and recent items.

# Push to the left (front)
LPUSH notifications:user1 "You have a new message"
LPUSH notifications:user1 "Your order shipped"

# Push to the right (back)
RPUSH queue:emails "email1" "email2"

# Get range (0 = first, -1 = last)
LRANGE notifications:user1 0 -1

# Pop from left (dequeue)
LPOP queue:emails
BLPOP queue:emails 0  # blocking pop — waits for an item

# Length
LLEN notifications:user1

Sets

Unordered collections of unique strings. Fast membership checks, intersections, and unions.

SADD user:1:tags "developer" "python" "mongodb"
SADD user:2:tags "developer" "javascript" "react"

# Check membership
SISMEMBER user:1:tags "python"  # 1 (true)
SISMEMBER user:1:tags "java"    # 0 (false)

# All members
SMEMBERS user:1:tags

# Intersection (common tags)
SINTER user:1:tags user:2:tags
# "developer"

# Union
SUNION user:1:tags user:2:tags

# Count
SCARD user:1:tags

Sorted Sets

Like sets, but every member has a score. Members are sorted by score. Perfect for leaderboards and rate limiting.

ZADD leaderboard 1500 "alex"
ZADD leaderboard 2300 "sam"
ZADD leaderboard 1800 "jordan"

# Get ranked (lowest to highest)
ZRANGE leaderboard 0 -1 WITHSCORES

# Get ranked (highest to lowest) — use ZRANGE ... REV in Redis 6.2+
ZRANGE leaderboard 0 2 BYSCORE REV WITHSCORES
# Legacy syntax (still works): ZREVRANGE leaderboard 0 2 WITHSCORES

# Get rank (0-indexed)
ZRANK leaderboard "alex"    # 0 (lowest)
ZREVRANK leaderboard "alex" # 2 (lowest when reversed)

# Get score
ZSCORE leaderboard "sam"   # "2300"

# Increment score
ZINCRBY leaderboard 100 "alex"

Hashes

Key-value maps stored under a single key. Great for storing objects.

HSET user:1 name "Alex" email "alex@example.com" age "28"
HGET user:1 name      # "Alex"
HGETALL user:1        # all fields and values
HMGET user:1 name age # multiple fields at once
HINCRBY user:1 age 1  # increment a numeric field
HDEL user:1 age       # delete a field
HEXISTS user:1 email  # 1 (true)

Expiration

Any key can have a TTL (time to live):

SET cache:product:5 "{...json...}"
EXPIRE cache:product:5 300     # expires in 300 seconds

# Set with expiration in one command
SET cache:product:5 "{...json...}" EX 300

# Check remaining TTL
TTL cache:product:5   # seconds remaining
PTTL cache:product:5  # milliseconds remaining
# -1 = no expiration, -2 = key doesn't exist

Node.js with ioredis

npm install ioredis
import Redis from "ioredis";

const redis = new Redis({
  host: "localhost",
  port: 6379,
});

// String operations
await redis.set("user:1:name", "Alex Johnson");
await redis.setex("session:abc", 3600, "user_data");
const name = await redis.get("user:1:name");

// Hash
await redis.hset("user:1", { name: "Alex", email: "alex@example.com", age: "28" });
const user = await redis.hgetall("user:1");

// Sorted set (leaderboard)
await redis.zadd("leaderboard", 1500, "alex");
const top3 = await redis.zrevrange("leaderboard", 0, 2, "WITHSCORES");

// Pipeline — send multiple commands in one round trip
const pipeline = redis.pipeline();
pipeline.set("key1", "val1");
pipeline.incr("counter");
pipeline.expire("key1", 60);
await pipeline.exec();

Python with redis-py

pip install redis
import redis

r = redis.Redis(host="localhost", port=6379, decode_responses=True)

# String
r.set("user:1:name", "Alex Johnson")
r.setex("session:abc", 3600, "user_data")
name = r.get("user:1:name")

# Hash
r.hset("user:1", mapping={"name": "Alex", "email": "alex@example.com"})
user = r.hgetall("user:1")

# Sorted set
r.zadd("leaderboard", {"alex": 1500, "sam": 2300})
top = r.zrevrange("leaderboard", 0, 2, withscores=True)

# Pipeline
with r.pipeline() as pipe:
    pipe.set("key1", "val1")
    pipe.incr("counter")
    pipe.expire("key1", 60)
    pipe.execute()

What’s Next?

You know the data types. Now let’s use them for the most common Redis use case: caching.

Next: Database Tutorial #14: Redis Caching Patterns