Redis Tutorial: Learn In-Memory Database from Scratch (2026)
Redis is the tool I reach for when I need speed. I have used it for caching, session storage, rate limiting, message queues, and even as a primary database for certain high-throughput use cases. The beauty of Redis is its simplicity: every command does one thing and does it fast. This tutorial covers the core data structures, persistence options, and production patterns I have refined over years of running Redis at scale.
Getting Started with Redis
Redis is an open-source, in-memory data structure store that can be used as a database, cache, message broker, and streaming engine. It supports strings, hashes, lists, sets, sorted sets, bitmaps, hyperloglogs, and geospatial indexes. All data resides in RAM, which gives Redis its legendary sub-millisecond response times.
Installation is straightforward. Use your package manager: apt-get install redis-server on Ubuntu, brew install redis on macOS, or download the Windows build from Microsoft's archive. After starting the redis-server process, connect with redis-cli. The PING command should return PONG, confirming everything works.
# Start Redis server
redis-server
# In another terminal, connect and test
redis-cli
127.0.0.1:6379> SET user:1000:name "Alice"
OK
127.0.0.1:6379> GET user:1000:name
"Alice"
127.0.0.1:6379> INCR visitor_count
(integer) 1
Core Data Structures in Depth
Redis strings are the foundation. They store text, numbers, or binary data up to 512MB. Use SET and GET for basic operations, INCR and DECR for atomic counters, and APPEND for concatenation. Strings are the building block for caching, rate limiting, and distributed locks.
Lists are linked lists of strings. LPUSH adds to the head, RPUSH adds to the tail, LPOP removes from the head, RPOP removes from the tail. Lists are perfect for message queues and activity feeds. LRANGE lets you paginate through list elements without popping them. The linked list structure means insertions are O(1), but indexed access is O(n).
Sorted sets are Redis's most versatile structure. Each member has a score, and members are ordered by score. Use ZADD to add members, ZRANGEBYSCORE to query by score range, ZRANK to get position, and ZREM to remove. Sorted sets power leaderboards, priority queues, and time-series data where timestamps are used as scores.
# Working with sorted sets
ZADD leaderboard 100 "player1"
ZADD leaderboard 85 "player2"
ZADD leaderboard 95 "player3"
# Get top 3 players
ZREVRANGE leaderboard 0 2 WITHSCORES
# Get player rank
ZRANK leaderboard "player2"
# Increment score atomically
ZINCRBY leaderboard 10 "player2"
Caching Strategies and TTL
Caching is the most common Redis use case. The key insight is setting appropriate Time-To-Live (TTL) values. Without TTL, stale data lives forever and memory fills up. Use EXPIRE to set a timeout on any key. SET with the EX option combines set and expire into a single atomic command.
The cache-aside pattern is the most popular strategy. On a read, check Redis first. If found, return it. If not, read from the database, store in Redis with a TTL, and return. On a write, update the database and invalidate the cache key. This keeps the cache fresh while avoiding the complexity of write-through caching.
Cache invalidation is the hardest problem in computer science, and Redis gives you tools to handle it. Use EXPIRE to auto-evict stale entries, DEL to manually invalidate, and the LRU eviction policy to handle memory pressure. When memory runs out, Redis evicts keys based on the configured policy. allkeys-lru evicts the least recently used keys regardless of TTL.
# Cache-aside pattern in Node.js
const user = await redis.get(`user:${userId}`);
if (user) return JSON.parse(user);
const dbUser = await db.findUser(userId);
await redis.setEx(
`user:${userId}`,
3600, // TTL in seconds
JSON.stringify(dbUser)
);
return dbUser;
Pub/Sub, Streams, and Messaging Patterns
Redis Pub/Sub provides a simple publish-subscribe messaging system. Publishers send messages to channels, and subscribers receive messages in real time. This is useful for chat applications, live notifications, and broadcasting events. The catch is that messages are fire-and-forget. If a subscriber is not connected, it misses the message.
Redis Streams solve this limitation. Streams are append-only logs that persist messages. Consumers can read from any point in the stream, acknowledge messages, and even have multiple consumer groups processing the same stream independently. Streams are ideal for event sourcing, activity tracking, and reliable message queues.
I prefer Redis Streams over Pub/Sub for anything that needs reliability. With streams, you can create a consumer group that tracks which messages each consumer has processed. If a consumer crashes, another picks up from the last acknowledged message. This gives you at-least-once delivery semantics, which is essential for payment processing and order workflows.
# Producer
XADD order_events * event_type "order.placed" user_id 1001 amount 49.99
# Consumer group
XGROUP CREATE order_events payment_workers $
# Consumer reading new messages
XREADGROUP GROUP payment_workers worker1 \
BLOCK 5000 COUNT 10 \
STREAMS order_events >
# Acknowledge processing
XACK order_events payment_workers 1718000000000-0
Persistence and High Availability
Redis stores data in memory by default, but it offers two persistence mechanisms. RDB (Redis Database) snapshots the entire dataset at configured intervals. It is compact and perfect for backups. AOF (Append-Only File) logs every write operation and provides better durability. You can use both simultaneously, which is what I recommend for production.
Redis Sentinel provides high availability. A Sentinel cluster monitors your master and replica instances. If the master fails, Sentinel promotes a replica to master and updates the configuration. Applications connect through Sentinel, which provides the current master address. Sentinel requires at least three instances for a quorum.
Redis Cluster goes beyond high availability to horizontal scaling. It shards data across multiple nodes using hash slots. Each node handles a subset of the 16384 hash slots. Clients connect to any node, which redirects them to the correct node. Cluster mode supports automatic failover and resharding, but it sacrifices multi-key operations across slots.
# redis.conf persistence settings
save 900 1 # snapshot if at least 1 key changed in 900s
save 300 10 # snapshot if at least 10 keys changed in 300s
save 60 10000 # snapshot if at least 10000 keys changed in 60s
appendonly yes
appendfsync everysec
# Sentinel configuration (sentinel.conf)
sentinel monitor mymaster 127.0.0.1 6379 2
sentinel down-after-milliseconds mymaster 5000
sentinel failover-timeout mymaster 60000
Lua Scripting and Redis Modules
Redis supports Lua scripting through the EVAL command. Lua scripts run atomically on the server, meaning no other commands execute during script execution. This is invaluable for implementing custom transactions and complex operations that would otherwise require multiple round trips. The script can access Redis commands via the redis.call() function.
Redis modules extend the core functionality. RediSearch adds full-text search with indexing, querying, and aggregation. RedisJSON provides native JSON document storage with path-based updates. RedisTimeSeries handles time-series data with downsampling and aggregation. RedisBloom adds probabilistic data structures like Bloom filters and count-min sketches.
Using modules can significantly reduce application complexity. Instead of managing search logic in your application code, let RediSearch handle indexing and querying. Instead of implementing a custom rate-limiting algorithm, use Redis with the RedisCell module. The module ecosystem is one of Redis's strongest advantages for specialized workloads.
# Lua script for atomic transfer
local balance = redis.call('GET', KEYS[1])
if tonumber(balance) < tonumber(ARGV[1]) then
return -1
end
redis.call('DECRBY', KEYS[1], ARGV[1])
redis.call('INCRBY', KEYS[2], ARGV[1])
return 0
# Run it
EVAL "script_here" 2 source:1000 dest:2000 50
Frequently Asked Questions
Is Redis just a cache?
No. Redis is a full-featured data structure server used for caching, messaging, streaming, rate limiting, session storage, and even as a primary database when data fits in memory and durability requirements are managed.
What happens when Redis runs out of memory?
Redis returns OOM errors for write commands. Configure an eviction policy like allkeys-lru or volatile-ttl. If you need more memory, add more RAM or use Redis Cluster for horizontal scaling.
How durable is Redis with AOF persistence?
With appendfsync everysec, you may lose at most one second of data. With appendfsync always, every write is fsynced, but throughput drops significantly. RDB snapshots also provide durability with configurable intervals.
What is the difference between Redis and Memcached?
Redis supports rich data structures, persistence, replication, Lua scripting, and many more features. Memcached is a simpler key-value cache. Redis is generally preferred for new projects.
Originally published on Ayodhyyya. Last updated June 1, 2026.