DEV Community

Cover image for Mastering Redis from the Command Line: A Hands-On Practice Guide
Md Abu Musa
Md Abu Musa

Posted on

Mastering Redis from the Command Line: A Hands-On Practice Guide

The fastest way to learn Redis is to type commands, watch the replies, and break things on purpose.

Getting started

Open a terminal, run redis-cli, and confirm the server answers. Use FLUSHDB between sections for a clean slate, but only on a practice instance.

PING                  # PONG
INFO server
INFO memory
INFO keyspace
SELECT 1              # switch to database 1
DBSIZE
CONFIG GET maxmemory
Enter fullscreen mode Exit fullscreen mode

Two shell flags are worth learning on day one: redis-cli -n 2 PING targets a specific database, and redis-cli --raw GET key prints values without quoting or escaping.

Core data types

Most real Redis usage is built from six structures. Run every command, and note each return value: OK, (integer), or nil.

Strings

SET user:1:name "Musa"
GET user:1:name
SET counter 10
INCR counter              # 11
INCRBY counter 5          # 16
APPEND user:1:name " Abu"
MSET a 1 b 2 c 3
MGET a b c
SET lock:x 1 NX EX 30     # only if absent, 30s TTL
SET k v XX                # only if present
GETEX k EX 60
Enter fullscreen mode Exit fullscreen mode

Keys and expiry

EXISTS user:1:name
TYPE user:1:name
EXPIRE user:1:name 60
TTL user:1:name
PERSIST user:1:name
UNLINK k                  # asynchronous delete
SCAN 0 MATCH user:* COUNT 100
OBJECT ENCODING counter   # int, embstr or raw
Enter fullscreen mode Exit fullscreen mode

Compare KEYS * with SCAN, and never use KEYS in production: it blocks the server while it walks the whole keyspace. Then set a 5-second TTL and run TTL repeatedly to watch the key expire.

Hashes

HSET user:1 name Musa age 30 city Dhaka
HGET user:1 name
HMGET user:1 name city
HGETALL user:1
HINCRBY user:1 age 1
HEXISTS user:1 city
HDEL user:1 city
HSCAN user:1 0
Enter fullscreen mode Exit fullscreen mode

Lists

RPUSH queue job1 job2 job3
LPUSH queue job0
LRANGE queue 0 -1
LPOP queue
LTRIM queue 0 99
BLPOP queue 10            # blocking pop; try from a second terminal
LMOVE queue processing LEFT RIGHT
Enter fullscreen mode Exit fullscreen mode

For a reliable queue, move each job with LMOVE queue processing, process it, then remove it with LREM processing 1 job.

Sets

SADD tags:post1 redis db cache
SADD tags:post2 redis golang
SISMEMBER tags:post1 redis
SINTER tags:post1 tags:post2
SUNION tags:post1 tags:post2
SDIFF tags:post1 tags:post2
SPOP tags:post1
Enter fullscreen mode Exit fullscreen mode

Sorted sets

ZADD leaderboard 100 alice 250 bob 175 carol
ZRANGE leaderboard 0 -1 WITHSCORES
ZRANGE leaderboard 0 2 REV WITHSCORES    # top 3 (Redis 6.2+)
ZRANK leaderboard alice
ZINCRBY leaderboard 50 alice
ZRANGEBYSCORE leaderboard 100 200
ZREM leaderboard carol
Enter fullscreen mode Exit fullscreen mode

Sorted sets are the most versatile structure on this list: leaderboards, priority queues, time-ordered indexes and rate limiters all reduce to them.

Beyond the basics

These structures trade generality for extreme efficiency, and each solves one problem very well.

Bitmaps, HyperLogLog and geo

Bitmaps track yes/no flags per user ID in a few bytes each. HyperLogLog counts unique items approximately in about 12 KB, however many there are. Geo commands store coordinates and answer distance and radius queries.

SETBIT login:2026-10-12 1001 1
GETBIT login:2026-10-12 1001
BITCOUNT login:2026-10-12
BITOP AND active:both login:day1 login:day2

PFADD visitors:today u1 u2 u3 u1
PFCOUNT visitors:today          # 3
PFMERGE visitors:week visitors:d1 visitors:d2

GEOADD shops 90.4125 23.8103 "dhaka-a" 91.8123 22.3569 "ctg-a"
GEODIST shops dhaka-a ctg-a km
GEOSEARCH shops FROMLONLAT 90.4 23.8 BYRADIUS 50 km ASC
Enter fullscreen mode Exit fullscreen mode

Streams

Streams are an append-only log with consumer groups, which makes them the durable alternative to Pub/Sub and lists for event processing.

XADD orders * user 1 amount 500
XLEN orders
XRANGE orders - +
XREAD BLOCK 5000 STREAMS orders $

XGROUP CREATE orders workers $ MKSTREAM
XREADGROUP GROUP workers w1 COUNT 1 STREAMS orders >
XACK orders workers <id>
XPENDING orders workers
XCLAIM orders workers w2 60000 <id>
XTRIM orders MAXLEN ~ 1000
Enter fullscreen mode Exit fullscreen mode

Use two terminals: one producer, one consumer-group worker. Kill the worker before it runs XACK, then recover the unacknowledged message with XPENDING and XCLAIM. That exercise teaches more about delivery guarantees than any documentation page.

Messaging and atomicity

Redis is single-threaded for command execution, so a single command is always atomic. The tools below extend that guarantee to groups of commands.

Pub/Sub

In terminal A, subscribe. In terminal B, publish.

# Terminal A
SUBSCRIBE news
PSUBSCRIBE news:*

# Terminal B
PUBLISH news "hello"
PUBSUB CHANNELS
PUBSUB NUMSUB news
Enter fullscreen mode Exit fullscreen mode

Pub/Sub is fire-and-forget: a subscriber that connects late misses earlier messages. Confirm this yourself, then contrast it with Streams, which keep history.

Transactions

MULTI
SET balance 100
DECRBY balance 30
EXEC

WATCH balance             # optimistic locking
MULTI
DECRBY balance 10
EXEC                      # nil if another client changed balance
Enter fullscreen mode Exit fullscreen mode

Trigger a WATCH failure by modifying balance from a second terminal before EXEC. Also note that Redis transactions have no rollback: if one command fails at runtime, the others still run.

Lua scripting

A Lua script runs as one atomic unit, which is the right tool for read-modify-write logic that WATCH makes clumsy.

EVAL "return redis.call('GET', KEYS[1])" 1 user:1:name

# Safe unlock: delete only if the token matches
EVAL "if redis.call('get',KEYS[1])==ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end" 1 lock:x token123

SCRIPT LOAD "return 'hi'"
EVALSHA <sha> 0
Enter fullscreen mode Exit fullscreen mode

Running Redis

Knowing the commands is half the job. The other half is knowing how Redis behaves when memory fills, a process restarts, or a client misbehaves.

Persistence

CONFIG GET save
BGSAVE
LASTSAVE
CONFIG SET appendonly yes
BGREWRITEAOF
INFO persistence
Enter fullscreen mode Exit fullscreen mode

Set a key, run SHUTDOWN SAVE, restart with sudo systemctl restart redis-server, and check that the key survived. Then repeat with persistence disabled and watch the data disappear.

Memory and eviction

CONFIG SET maxmemory 10mb
CONFIG SET maxmemory-policy allkeys-lru
MEMORY USAGE user:1
INFO stats                # evicted_keys, keyspace_hits, keyspace_misses
Enter fullscreen mode Exit fullscreen mode
redis-cli --bigkeys
redis-cli --memkeys
Enter fullscreen mode Exit fullscreen mode

Fill memory with a loop and watch evicted_keys climb. Try noeviction, volatile-lru and allkeys-lfu to see how each policy changes which keys survive.

Monitoring and debugging

MONITOR                   # live command stream; development only
SLOWLOG GET 10
CONFIG SET slowlog-log-slower-than 1000
CLIENT LIST
LATENCY DOCTOR
Enter fullscreen mode Exit fullscreen mode
redis-cli --latency
redis-cli --stat
redis-benchmark -q -n 100000 -c 50
Enter fullscreen mode Exit fullscreen mode

Security and ACLs

CONFIG SET requirepass strongpass
AUTH strongpass
ACL SETUSER reader on >readpass ~cache:* +get +mget
ACL LIST
AUTH reader readpass
Enter fullscreen mode Exit fullscreen mode

Log in as reader and confirm that SET fails with NOPERM. Least-privilege users are one of the cheapest hardening steps Redis offers.

Replication on one machine

Copy the config, change the port, data directory and pidfile, then start a replica:

sudo cp /etc/redis/redis.conf /etc/redis/redis-6380.conf
redis-server /etc/redis/redis-6380.conf --replicaof 127.0.0.1 6379
Enter fullscreen mode Exit fullscreen mode
INFO replication
WAIT 1 100
REPLICAOF NO ONE          # promote the replica
Enter fullscreen mode Exit fullscreen mode

Write on the primary and read on the replica. Then try writing to the replica to see the read-only error.

Real-world patterns

Once the commands feel natural, combine them into the patterns production systems actually use.

Pattern Commands
Cache-aside GET product:5; on a miss, SET product:5 <json> EX 300
Fixed-window rate limiter INCR rate:user1:202610121530, then EXPIRE it to 60 seconds; reject above the limit
Distributed lock SET lock:order:9 <token> NX PX 10000; release with the Lua compare-and-delete script
Leaderboard ZINCRBY to score, ZRANGE ... REV to read the top N
Session store Hash session:<id>, with EXPIRE refreshed on each request
Unique visitors PFADD and PFCOUNT
Daily active users One bitmap per date, combined with BITOP
Job queue List with BLPOP, or Streams with consumer groups
Idempotency key SET idem:<key> 1 NX EX 86400

The distributed lock deserves special care. Always store a unique token as the value and release with the Lua script, so one client can never delete a lock another client now holds.

Challenges

Try these without looking anything up. Each one forces you to combine commands you have already met.

  1. Build a sliding-window rate limiter with a sorted set, using ZADD, ZREMRANGEBYSCORE and ZCARD.
  2. Keep a "recently viewed, last 10 items" list per user with LPUSH and LTRIM.
  3. Implement a delayed job queue with a sorted set scored by run timestamp.
  4. Build autocomplete with ZRANGEBYLEX.
  5. Write a Lua script that decrements stock atomically and refuses to go below zero.
  6. Compare the memory used by 10,000 small keys against one hash with 10,000 fields, using MEMORY USAGE.

The last exercise tends to surprise people: small hashes use a compact encoding, so the single hash is often far cheaper.

Conclusion

Redis rewards hands-on practice more than reading. Work through the sections in order, break things deliberately (kill a worker mid-stream, fill memory, fail a WATCH), and finish with the challenges.

Top comments (0)