Skip to main content

Redis

What is Redis?

Redis stands for REmote DIctionary Server, though that formal definition hardly does justice to what it's become. At its core, Redis is an in-memory data structure store that can function as a database, cache, message broker, and streaming engine. It's blazingly fast, refreshingly simple to use, and has become the de facto standard for caching in modern web applications.

The key phrase here is "in-memory." Redis keeps all data in RAM, which is why it's so fast—memory access is orders of magnitude faster than disk access. When you need microsecond response times for reads and writes, Redis is often the answer.

Why Redis Matters

Redis solves several critical problems in modern application development:

  • Performance: Serving data from memory is dramatically faster than disk-based databases
  • Simplicity: The API is straightforward—no complex query languages to learn
  • Versatility: Beyond caching, it supports pub/sub messaging, geospatial queries, and more
  • Scalability: Handles millions of operations per second on modest hardware

Redis vs Traditional Databases

Understanding what Redis is requires understanding what it isn't. Redis is not a replacement for your relational database (PostgreSQL, MySQL) or document store (MongoDB). Here's why:

AspectRedisTraditional DB (Postgres)
StorageIn-memory (RAM)Disk-based (with memory cache)
SpeedMicrosecondsMilliseconds
Data SizeLimited by RAMLimited by disk
DurabilityConfigurable (optional)Guaranteed (ACID)
Query CapabilityKey-based, simpleSQL, complex queries
CostRAM is expensiveDisk is cheap

Redis complements traditional databases—it doesn't replace them. Your database remains the source of truth; Redis provides a high-speed read layer for frequently accessed data.

Core Concepts

Key-Value Store

At its most basic, Redis is a key-value store. You store data using a key (a string) and retrieve it using that same key. Think of it as a giant hash table or dictionary:

┌─────────────────────────────────────┐
│ Redis Memory Space │
│ │
│ "user:1001" → "John Doe" │
│ "session:abc" → {...session data} │
│ "cache:products" → [...products] │
│ "counter:views" → 42 │
│ │
└─────────────────────────────────────┘

Every piece of data in Redis has a key. Keys are strings, and they're your only way to access data—there's no scanning through tables or running complex queries.

Data Structures

Unlike many key-value stores that only support string values, Redis supports multiple data structures. This flexibility makes it powerful for different use cases:

Strings

The most basic type. Store any data serializable to a string (text, JSON, numbers, binary data).

# Set a value
SET user:1001:name "John Doe"

# Get a value
GET user:1001:name
# Returns: "John Doe"

# Store JSON
SET user:1001:profile '{"name":"John","age":35}'

# Increment a counter atomically
INCR page:views:homepage
# Returns: 1
INCR page:views:homepage
# Returns: 2

Lists

Ordered collections of strings. Perfect for queues, activity feeds, or recent items.

# Push items to a list
LPUSH notifications:user:1001 "New message from Alice"
LPUSH notifications:user:1001 "Order shipped"

# Get list items
LRANGE notifications:user:1001 0 -1
# Returns: ["Order shipped", "New message from Alice"]

# Pop from list (useful for queues)
RPOP notifications:user:1001
# Returns: "New message from Alice"

Sets

Unordered collections of unique strings. Great for tags, unique visitors, or membership checks.

# Add members to a set
SADD user:1001:tags "developer" "python" "golang"

# Check membership
SISMEMBER user:1001:tags "python"
# Returns: 1 (true)

# Get all members
SMEMBERS user:1001:tags
# Returns: ["developer", "python", "golang"]

# Set operations
SADD user:1002:tags "developer" "javascript" "react"
SINTER user:1001:tags user:1002:tags
# Returns: ["developer"] (intersection)

Sorted Sets

Like sets, but each member has a score allowing ordering. Excellent for leaderboards, priority queues, or time-series data.

# Add scored members
ZADD leaderboard 1500 "player:alice"
ZADD leaderboard 2300 "player:bob"
ZADD leaderboard 1800 "player:charlie"

# Get top players
ZREVRANGE leaderboard 0 2 WITHSCORES
# Returns: ["player:bob", "2300", "player:charlie", "1800", "player:alice", "1500"]

# Get player rank
ZREVRANK leaderboard "player:bob"
# Returns: 0 (1st place)

Hashes

Maps between string fields and values. Perfect for representing objects.

# Set multiple fields
HSET user:1001 name "John Doe" email "john@example.com" age 35

# Get a field
HGET user:1001 name
# Returns: "John Doe"

# Get all fields
HGETALL user:1001
# Returns: ["name", "John Doe", "email", "john@example.com", "age", "35"]

# Increment a numeric field
HINCRBY user:1001 age 1
# Returns: 36

Keys and Expiration

Keys in Redis are strings, but convention matters. Use namespacing to organize keys:

# Good key patterns
user:1001:profile
session:abc123
cache:products:electronics
rate_limit:api:192.168.1.1:2024-02-19

# Set key with expiration (TTL)
SET session:abc123 "session_data" EX 3600
# Expires in 3600 seconds (1 hour)

# Check time to live
TTL session:abc123
# Returns: 3595 (seconds remaining)

# Set expiration on existing key
EXPIRE user:1001:profile 7200
# Expires in 2 hours

Expiration is crucial in Redis. It allows automatic cleanup of stale data, which is essential for:

  • Session management (expire old sessions)
  • Caching (expire cached data to force refresh)
  • Rate limiting (expire counters after time window)

Persistence

Redis is primarily an in-memory store, but it offers persistence options:

RDB (Redis Database Backup)

Point-in-time snapshots saved to disk at configured intervals. Fast and compact, but you may lose data between snapshots.

AOF (Append-Only File)

Logs every write operation. More durable but slower and larger files. Can be replayed to reconstruct data.

No Persistence

Maximum speed, zero durability. Acceptable for truly ephemeral data like caching.

For caching scenarios, you typically use RDB or no persistence—losing cached data isn't catastrophic since it can be rebuilt from the source database.

Common Patterns

Caching

The most common Redis use case. Store database query results in Redis to avoid expensive DB hits:

# Check cache first
GET cache:user:1001
# Returns: null (cache miss)

# (Application queries database, then caches result)
SET cache:user:1001 '{"id":1001,"name":"John"}' EX 300
# Cached for 5 minutes

# Subsequent request
GET cache:user:1001
# Returns: '{"id":1001,"name":"John"}' (cache hit)

Session Storage

Store user session data with automatic expiration:

# Create session
SET session:xyz789 '{"user_id":1001,"logged_in":true}' EX 1800
# Session expires in 30 minutes

# Extend session on activity
EXPIRE session:xyz789 1800
# Reset TTL to 30 minutes

Rate Limiting

Track request counts per time window:

# Track requests per minute
INCR rate:api:192.168.1.1:minute:2024-02-19-15:30
EXPIRE rate:api:192.168.1.1:minute:2024-02-19-15:30 60

# Check if over limit
GET rate:api:192.168.1.1:minute:2024-02-19-15:30
# Returns: "15" (requests this minute)

Pub/Sub Messaging

Simple message broadcasting between application components:

# Subscribe to channels (in one client)
SUBSCRIBE notifications

# Publish messages (in another client)
PUBLISH notifications "New order received"
# All subscribers receive the message

Common Commands

Essential Redis CLI commands you'll use regularly:

# Connection and info
redis-cli # Connect to Redis
PING # Test connection (returns PONG)
INFO # Server information
DBSIZE # Number of keys

# Key operations
KEYS * # List all keys (use cautiously in production)
EXISTS user:1001 # Check if key exists
DEL user:1001 # Delete key
TYPE user:1001 # Get value type
RENAME oldkey newkey # Rename key

# Database management
FLUSHDB # Delete all keys in current database
FLUSHALL # Delete all keys in all databases
SELECT 1 # Switch to database 1 (default is 0)

# Monitoring
MONITOR # Real-time command stream (debug only)
SLOWLOG GET 10 # Get 10 slowest queries

# Transactions
MULTI # Start transaction
SET key1 "value1"
SET key2 "value2"
EXEC # Execute transaction

Performance Characteristics

Redis is fast—seriously fast. On modern hardware, a single Redis instance can handle:

  • 100,000+ operations per second for simple operations
  • Sub-millisecond latency for most operations
  • Millions of keys (limited only by available RAM)

What Makes Redis Fast?

  1. In-Memory Storage: RAM access is ~100,000x faster than SSD
  2. Simple Data Model: No complex query planning or optimization
  3. Single-Threaded: No locking overhead (though Redis 6+ has threaded I/O)
  4. Efficient Protocol: Binary-safe RESP protocol with minimal overhead

Memory Management

Since Redis stores everything in RAM, memory is precious:

# Check memory usage
INFO memory

# Get key size
MEMORY USAGE user:1001
# Returns: 72 (bytes)

# Set memory limit in redis.conf
maxmemory 2gb
maxmemory-policy allkeys-lru # Evict least recently used keys

Common eviction policies:

  • noeviction: Return errors when memory is full (default)
  • allkeys-lru: Evict least recently used keys
  • volatile-lru: Evict LRU keys with TTL set
  • allkeys-random: Evict random keys
  • volatile-ttl: Evict keys with shortest TTL first

Redis in Development

For local development, running Redis in Docker is the standard approach:

# Run Redis in Docker
docker run -d -p 6379:6379 redis:7-alpine

# Connect with CLI
docker exec -it <container-name> redis-cli

# Or install locally
# Ubuntu/Debian
sudo apt-get install redis-server

# macOS
brew install redis

When to Use Redis

Redis excels at:

  • Caching: The primary use case—cache database queries, API responses, computed results
  • Session storage: Fast, with automatic expiration
  • Real-time analytics: Counters, leaderboards, time-series data
  • Rate limiting: Track requests per time window
  • Pub/Sub messaging: Simple event broadcasting
  • Temporary data: Any data that's inherently ephemeral

When Not to Use Redis

Skip Redis when:

  • Primary data storage: Use a proper database; Redis should complement, not replace
  • Large datasets: RAM is expensive; if data exceeds available memory, use disk-based storage
  • Complex queries: Redis doesn't support joins, complex filtering, or SQL-style queries
  • Strict durability requirements: Even with AOF, Redis prioritizes speed over guaranteed persistence
  • No performance problem: Don't cache prematurely; measure first

The Caching Decision

The hardest part about caching isn't Redis itself—it's deciding what to cache and for how long. Cache too aggressively and you serve stale data; cache too conservatively and you don't get performance benefits.

Consider caching when:

  • Data is read frequently but changes infrequently
  • Generating the data is expensive (complex query, external API call, heavy computation)
  • Serving slightly stale data is acceptable

Skip caching when:

  • Data changes constantly
  • Data is accessed infrequently
  • The read operation is already fast
  • Data staleness would cause serious problems

The Bigger Picture

Redis has become infrastructure table stakes. Like PostgreSQL or Nginx, it's a tool that's expected to be in the stack. Its simplicity is its strength—there's no complex setup, no query language to master, no schema to design. You set keys, you get keys, and it's fast.

The beauty of Redis is that it solves problems elegantly without adding complexity. Need caching? Add Redis. Need sessions? Add Redis. Need a leaderboard? Add Redis. The API is consistent, the performance is predictable, and it just works.


For more information, see the official Redis documentation.