Redis Hashes
Hashes are maps between string fields and string values—perfect for representing objects. They're memory-efficient when storing many small key-value pairs and provide O(1) access to individual fields.
When Redis Hashes Are the Right Choice
Hashes are a good fit when a single key represents an object with multiple fields, such as a user profile, shopping cart, or settings blob. They let you change one field without rewriting the entire value.
Key Characteristics
• Can store up to 4 billion field-value pairs • Memory-optimized for small hashes (ziplist encoding) • Supports partial updates without reading/writing entire object • Ideal for user profiles, product details, configuration objects
Basic Operations
# Set and get fields
HSET user:1000 name "Alice" email "alice@example.com" age 28
HGET user:1000 name # Get single field → "Alice"
HMGET user:1000 name email # Get multiple fields
HGETALL user:1000 # Get all field-value pairs
# Check field count
HLEN user:1000 # Number of fields → 3Incrementing Numeric Fields
Hash fields can store integers and floats that Redis can increment atomically.
HSET user:1000 age 28 balance 100.50
HINCRBY user:1000 age 1 # Increment age → 29
HINCRBY user:1000 age -5 # Decrement age → 24
HINCRBYFLOAT user:1000 balance 99.50 # Add to balance → 200.00
HINCRBYFLOAT user:1000 balance -50.25 # Subtract → 149.75Field Existence and Deletion
HEXISTS user:1000 phone # Check if field exists → 0
HSETNX user:1000 phone "555-1234" # Set only if field doesn't exist
HDEL user:1000 phone # Delete field
HDEL user:1000 field1 field2 field3 # Delete multiple fieldsMetadata Operations
HKEYS user:1000 # Get all field names
HVALS user:1000 # Get all values
HLEN user:1000 # Count of fields → 3
HSTRLEN user:1000 name # Length of field valueScanning Large Hashes
Use HSCAN for non-blocking iteration over large hashes.
# Iterate with cursor (non-blocking)
HSCAN user:1000 0 COUNT 10 # Start from cursor 0
HSCAN user:1000 17 COUNT 10 # Continue from returned cursor
HSCAN user:1000 0 MATCH email* COUNT 10 # Filter by patternUse Case: User Profiles
Store user attributes with granular field updates.
# Create user profile
HSET user:1000
username "alice"
email "alice@example.com"
created_at "2024-01-15"
login_count 0
premium false
# Update specific fields without touching others
HINCRBY user:1000 login_count 1
HSET user:1000 last_login "2024-01-16T10:30:00Z"
HSET user:1000 premium true
# Get profile
HGETALL user:1000Use Case: Shopping Cart
Product IDs as fields, quantities as values.
cart_key = "cart:user:123"
# Add items
HSET cart_key "product:abc" 2 # 2x Product ABC
HSET cart_key "product:xyz" 1 # 1x Product XYZ
# Update quantity
HINCRBY cart_key "product:abc" 1 # Add one more → 3
HINCRBY cart_key "product:abc" -1 # Remove one → 2
# Remove item
HDEL cart_key "product:xyz"
# Get cart contents
HGETALL cart_key
# Clear cart
DEL cart_keyUse Case: Daily Statistics
Multiple counters under one key, organized by date.
stats_key = "stats:page:home"
# Increment daily views
HINCRBY stats_key "2024-01-15" 1
HINCRBY stats_key "2024-01-16" 1
HINCRBY stats_key "2024-01-16" 1
# Get all daily counts
HGETALL stats_key
# Returns: {"2024-01-15": "1", "2024-01-16": "2"}
# Get specific day
HGET stats_key "2024-01-16"Memory Efficiency
Hashes use ziplist encoding when small, which is very memory-efficient. Configure thresholds in redis.conf:
# redis.conf settings
hash-max-ziplist-entries 512 # Max fields for ziplist
hash-max-ziplist-value 64 # Max field/value size for ziplist
# Check encoding
OBJECT ENCODING user:1000 # → "ziplist" or "hashtable"
MEMORY USAGE user:1000 # Bytes used by keyCommon Redis Hash Mistakes
A common mistake is treating hashes like nested JSON documents. Hashes are flat field-value maps, so if your data is deeply nested or needs partial arrays, serializing part of the structure or choosing a different model may be cleaner.
Related
Compare hashes with strings, lists, sets, and zsets before locking in your data model.
Use strings when one key maps to one value and field-level access is unnecessary.
Switch to lists when ordering and queue behavior matter more than named fields.
Useful when you are comparing relational modeling tradeoffs with Redis object-style storage.