Basic Data Types
Introduction
Redis is not just a key-value store where values are plain strings. It gives you five fundamental data structures—String, List, Set, Hash, and Sorted Set—each designed for specific access patterns. This chapter introduces every core type, shows the commands you will use daily, and explains when to choose one over the others. Master these types and you will solve the majority of caching, messaging, and real-time ranking problems you encounter in production.
Prerequisites
- A running Redis server (see Installation and the Redis CLI)
- Basic comfort with
redis-clior any Redis client - No programming language is required; examples use
redis-clicommands
String
The String is the simplest Redis type, but do not let that fool you. It can hold text, integers, floats, or binary data up to 512 MB. Because Redis stores Strings in memory, reads and writes are consistently sub-millisecond.
Setting and Getting Values
MSET and MGET reduce network round trips. When you know you need three keys, fetching them in one command is faster than three separate GET calls.
Atomic Counters
Redis guarantees that INCR, DECR, and their variants are atomic even when hundreds of clients race to update the same key.
Tip
Counter Pattern
Use INCR for rate limiters, inventory counts, and view statistics. Because the operation is atomic, you never need distributed locks for simple increments.
Expiration and Conditional Sets
# Set a key that disappears after 60 seconds
SETEX session:token:abc123 60 "user_id=42"
# Set only if the key does not exist (useful for locks)
SETNX lock:report:generation "owner=job_7"
# (integer) 1
# SETNX returns 0 if the key already exists
SETNX lock:report:generation "owner=job_8"
# (integer) 0SETEX combines SET and EXPIRE into one atomic command. SETNX (Set if Not eXists) is the primitive behind distributed locking patterns you will see later in this track.
String Substring and Length Operations
# Append to a string
APPEND log:tail "[INFO] Server started\n"
# Get a substring (inclusive, zero-based)
GETRANGE user:1:bio 0 50
# Overwrite a portion of a string
SETRANGE user:1:bio 10 " engineer"
# Get the length in bytes
STRLEN user:1:bioList
A List in Redis is an ordered collection of strings, implemented as a doubly linked list. You can push or pop elements from either end in constant time.
Push and Pop
Tip
Queue vs Stack
Use LPUSH + RPOP (or the reverse) for a FIFO queue. Use LPUSH + LPOP for a LIFO stack.
Inspecting Lists
LTRIM is a powerful companion to LPUSH when you want to keep only the most recent N items, such as a user's latest 50 notifications.
Blocking Pop
# Wait up to 30 seconds for an element to become available
BLPOP queue:emails 30BLPOP and BRPOP block the client until another process pushes data into the list. This is the foundation of a simple, reliable task queue without external message broker software.
Set
A Set is an unordered collection of unique strings. Sets excel at membership tests, deduplication, and mathematical set operations.
Adding, Removing, and Checking Membership
Set Operations
# Find tags shared by two posts
SINTER post:42:tags post:43:tags
# Combine tags from two posts
SUNION post:42:tags post:43:tags
# Find tags unique to post 42
SDIFF post:42:tags post:43:tags
# Store the intersection into a new key
SINTERSTORE common:tags post:42:tags post:43:tagsTip
Social Graph Pattern
Store each user's friends as a Set. SINTER user:1:friends user:2:friends returns mutual friends instantly.
Hash
A Hash stores field-value pairs inside a single key. It is the Redis equivalent of a plain JavaScript object or a Python dictionary, and it is the most memory-efficient way to represent structured data in Redis.
Field Operations
Atomic Field Updates
# Increment a numeric field atomically
HINCRBY user:42 score 10
# (integer) 10
# Increment a float field
HINCRBYFLOAT product:7:metrics rating_avg 0.5Warning
Avoid the "String JSON" Trap
Developers sometimes store an entire JSON object as a single String: SET user:42 "{\"name\":\"Elena\"}". This forces you to fetch and overwrite the entire blob just to change one field. Use a Hash instead. It keeps memory low and allows per-field updates.
Sorted Set
A Sorted Set (or ZSet) is like a Set where every member has an associated floating-point score. Members are stored in ascending order by score, and no two members can be identical. Sorted Sets are the engine behind leaderboards, priority queues, and time-series windows.
Adding and Scoring
# Add players with their scores
ZADD leaderboard 1500 "alice"
ZADD leaderboard 1200 "bob"
ZADD leaderboard 1800 "carol"
# Update a score (adds if new, updates if exists)
ZINCRBY leaderboard 100 "alice"
# "1600"Range Queries
Counting and Removal
Tip
Time-Series Pattern
Store timestamps as scores and event IDs as members: ZADD events:system 1704067200 "server_restart". Query windows with ZRANGEBYSCORE and automatically expire old entries with ZREMRANGEBYSCORE.
Choosing the Right Type
| If you need... | Use | Example |
|---|---|---|
| A simple value, counter, or cache blob | String | Session token, page view count |
| A FIFO queue or activity feed | List | Background job queue, recent comments |
| Unique items with fast membership checks | Set | Tags, IP allowlists, friend lists |
| Structured objects with per-field access | Hash | User profile, product metadata |
| Ranked data or range queries by score | Sorted Set | Leaderboard, priority queue, timeline |
FAQ
Can I store nested objects like a Hash inside a Hash?
No. Redis values are flat. If you need nesting, store a JSON string in a String field, or flatten the structure across multiple Hash keys. Alternatively, use a document database such as MongoDB for deeply nested schemas.
What happens if I use LPOP on an empty List?
It returns (nil). If you use the blocking variant BLPOP, the client waits until another process pushes an element or the timeout expires.
Are Set operations like SINTER atomic?
Yes. All Redis commands are atomic because the server is single-threaded. A massive SINTER against huge Sets will block other commands briefly, but the result is always consistent.
**How does Redis store Hashes so efficiently??
Small Hashes (typically under a few hundred entries) are stored with a compact internal encoding called ziplist. When they grow beyond configurable thresholds, Redis converts them to a standard hash table automatically. You rarely need to think about this, but it explains why Hashes beat JSON strings on memory usage.
Can two members in a Sorted Set have the same score?
Yes. When scores tie, Redis sorts members lexicographically by the member name itself. This is deterministic and useful for alphabetical tie-breaking.
Is there a limit to how many elements a List or Set can hold?
Theoretical limits are in the hundreds of millions per key, bounded only by available memory. Practical limits are lower: extremely large keys cause latency spikes during deletion or serialization. Aim to keep individual keys under a few hundred thousand elements when possible.