redis · v2.0.0 · 2026-08-06 · sha256 75a07358b77fe6a0
redis v2.0.0A
Immutable. This exact content is served forever at /api/v1/blob/75a07358b77fe6a0.
---
name: redis
description: "Redis v8.0 - in-memory database, caching, pub/sub, sessions, rate limiting, data structures with RESP3 default and asyncio module"
metadata:
author: mte90
version: 2.0.0
tags:
- redis
- database
- caching
- pub-sub
- sessions
- rate-limiting
- data-structures
- nosql
- resp3
- asyncio
---
# Redis (redis-py v8.0)
Redis - in-memory data structure store, used as database, cache, and message broker.
**redis-py v8.0 changes:**
- Python 3.10+ required
- RESP3 is the default protocol (was RESP2 in 7.x)
- Async API: `redis.asyncio` module (not `.asyncio` property)
## Installation
```bash
pip install redis
```
## Basic Usage
### Synchronous Client
```python
import redis
# Default protocol is now RESP3
r = redis.Redis(host='localhost', port=6379, db=0)
# Basic commands
r.set('foo', 'bar')
value = r.get('foo') # b'bar'
# Close connection
r.close()
```
### RESP2 vs RESP3
```python
# RESP3 (default in v8.0)
r = redis.Redis(protocol=3)
# Opt back into RESP2
r = redis.Redis(protocol=2)
```
### Async Client
```python
import redis.asyncio as redis
async def example():
# Default protocol is RESP3
r = redis.Redis(host='localhost', port=6379, db=0)
await r.set('foo', 'bar')
value = await r.get('foo') # b'bar'
# Close connection
await r.aclose()
```
**Migration from v7.x:**
```python
# OLD (v7.x and earlier)
from redis import Redis
r = Redis()
client = r.asyncio # Property
# NEW (v8.0+)
import redis.asyncio as redis
r = redis.Redis()
```
## Connection Pool
```python
# Create a connection pool
pool = redis.ConnectionPool(
host='localhost',
port=6379,
db=0,
max_connections=50,
decode_responses=True,
socket_connect_timeout=5,
socket_timeout=5,
retry_on_timeout=True,
)
# Use pool with client
r = redis.Redis(connection_pool=pool)
```
### Connection Pool with Password
```python
pool = redis.ConnectionPool(
host='localhost',
port=6379,
password='your_password',
max_connections=100,
)
r = redis.Redis(connection_pool=pool)
```
## Core Commands
### Strings
```python
# Set
r.set('key', 'value')
r.set('key', 'value', ex=300) # Expiration in seconds
r.setnx('key', 'value') # Set if not exists
r.mset({'key1': 'value1', 'key2': 'value2'})
# Get
value = r.get('key')
values = r.mget(['key1', 'key2'])
# Delete
r.delete('key')
r.delete('key1', 'key2', 'key3')
# Exists
exists = r.exists('key')
# TTL
ttl = r.ttl('key') # Time to live in seconds
r.expire('key', 300) # Set expiration
```
### Hashes
```python
# Set hash field
r.hset('user:1', 'name', 'Alex')
r.hset('user:1', mapping={'name': 'Alex', 'email': 'alex@example.com'})
# Get hash field
name = r.hget('user:1', 'name')
user = r.hgetall('user:1') # All fields
# Check field exists
exists = r.hexists('user:1', 'name')
# Get all fields
fields = r.hkeys('user:1')
values = r.hvals('user:1')
# Delete field
r.hdel('user:1', 'name')
```
### Lists
```python
# Push to list
r.lpush('mylist', 'item1', 'item2')
r.rpush('mylist', 'item3')
# Pop from list
item = r.lpop('mylist')
item = r.rpop('mylist')
# Get range
items = r.lrange('mylist', 0, -1)
# List length
length = r.llen('mylist')
```
### Sets
```python
# Add to set
r.sadd('myset', 'item1', 'item2', 'item3')
# Check membership
exists = r.sismember('myset', 'item1')
# Get all members
members = r.smembers('myset')
# Remove from set
r.srem('myset', 'item1')
# Set operations
r.sunion('set1', 'set2')
r.sinter('set1', 'set2')
```
### Sorted Sets
```python
# Add to sorted set
r.zadd('scores', {'player1': 100, 'player2': 200})
# Get range by score
top_players = r.zrange('scores', 0, -1, withscores=True)
# Get range by rank
top_players = r.zrevrange('scores', 0, 9) # Top 10
# Remove from sorted set
r.zrem('scores', 'player1')
# Score of member
score = r.zscore('scores', 'player1')
```
## Redis Stack Modules
### Redis Search
```python
# Create index
r.ft().create_index((
TextField('name'),
NumericField('age'),
TagField('tags'),
))
# Search
results = r.ft().search('@name:alex @age:[20 30]')
# Drop index
r.ft().dropindex()
```
### Redis JSON
```python
from redis.commands.json.path import Path
# Set JSON document
r.json().set('/user:1', Path.root_path(), {
'name': 'Alex',
'age': 30,
'tags': ['developer', 'python'],
})
# Get JSON document
user = r.json().get('/user:1')
# Get specific field
name = r.json().get('/user:1', Path('$.name'))
# Merge update
r.json().merge('/user:1', Path.root_path(), {'age': 31})
# Delete field
r.json().del_('/user:1', Path('$.age'))
```
### Redis TimeSeries
```python
# Create time series
r.ts().create('sensor:1')
# Add data point
r.ts().add('sensor:1', '*', 25.3) # Current timestamp
r.ts().add('sensor:1', 1234567890, 25.5) # Specific timestamp
# Get range
data = r.ts().range('sensor:1', 0, '*')
# Add with aggregation
r.ts().add('sensor:1', '*', 25.3)
aggregated = r.ts().range('sensor:1', 0, '*', agg_type='avg', bucket_size=60000)
```
## Pipelines
```python
# Basic pipeline
pipe = r.pipeline()
pipe.set('key1', 'value1')
pipe.set('key2', 'value2')
pipe.get('key1')
results = pipe.execute() # [True, True, b'value1']
# Watch for transactions
pipe = r.pipeline(True)
pipe.watch('mykey')
val = pipe.get('mykey')
pipe.multi()
pipe.set('mykey', val + 1)
pipe.execute()
```
## Django Integration
### django-redis (still works with v8.0)
```bash
pip install django-redis
```
```python
# settings.py
CACHES = {
'default': {
'BACKEND': 'django_redis.cache.RedisCache',
'LOCATION': 'redis://127.0.0.1:6379/1',
'OPTIONS': {
'CLIENT_CLASS': 'django_redis.client.DefaultClient',
'CONNECTION_POOL_KWARGS': {
'max_connections': 50,
'retry_on_timeout': True,
'protocol': 3, # RESP3
},
'SOCKET_CONNECT_TIMEOUT': 5,
'SOCKET_TIMEOUT': 5,
},
'KEY_PREFIX': 'myapp',
'VERSION': 1,
}
}
```
```python
from django.core.cache import cache
# Set with expiration
cache.set('key', 'value', timeout=300)
# Get
value = cache.get('key', 'default_value')
# Delete
cache.delete('key')
cache.delete_pattern('user_*')
```
### Celery Broker
```python
# settings.py
CELERY_BROKER_URL = 'redis://127.0.0.1:6379/0'
CELERY_RESULT_BACKEND = 'redis://127.0.0.1:6379/1'
CELERY_ACCEPT_CONTENT = ['json']
CELERY_TASK_SERIALIZER = 'json'
CELERY_RESULT_SERIALIZER = 'json'
```
### Django Channels
```python
# settings.py
CHANNEL_LAYERS = {
'default': {
'BACKEND': 'channels_redis.core.RedisChannelLayer',
'CONFIG': {
'hosts': [('127.0.0.1', 6379)],
},
}
}
```
## Redis CLI
```bash
# Connect
redis-cli
# Check keys
KEYS *
# Delete by pattern (use with caution)
SCAN 0 MATCH user:* COUNT 1000 | xargs redis-cli DEL
# Clear current database
FLUSHDB
# Monitor commands
MONITOR
```
## Best Practices
### Connection Management
```python
from redis import ConnectionPool
# Reuse connection pool globally
pool = ConnectionPool.from_url('redis://localhost:6379/0', max_connections=50)
def get_redis():
return redis.Redis(connection_pool=pool)
```
### Key Design
```python
# Use namespaced keys
KEY_PREFIX = 'myapp'
VERSION = 1
# Keys become: myapp:v1:user:123
# Add TTL to all keys
cache.set('temp_token', token, timeout=300) # 5 min
# Use consistent naming
cache.set('user:profile:123', data)
cache.set('user:session:123', data)
```
### Performance
```python
# Batch operations
r.mset({'key1': 'value1', 'key2': 'value2', 'key3': 'value3'})
# Use pipeline for multiple ops
pipe = r.pipeline()
pipe.set('a', 1)
pipe.set('b', 2)
pipe.execute() # Atomic, single round-trip
# Use SCAN instead of KEYS * in production
cursor = 0
while True:
cursor, keys = r.scan(cursor, match='user:*', count=100)
# Process keys
if cursor == 0:
break
```
### Error Handling
```python
from redis.exceptions import ConnectionError, TimeoutError
try:
value = r.get('key')
except ConnectionError:
# Fallback to DB or default
value = get_from_db()
except TimeoutError:
# Handle timeout
value = get_cached_default()
```
### Do:
- Always set TTL (expire keys)
- Use key prefixes for namespacing
- Reuse connections (use connection pool)
- Use pipeline for batch operations
- Use SCAN instead of KEYS * in production
### Don't:
- Use KEYS * in production (blocks Redis)
- Store large values (>1MB consider compression)
- Use Redis as primary data store (it's a cache)
- Forget connection timeout settings
- Create new connection per request
## Migration from v7.x
### Breaking Changes
1. **Python 3.10+ required**
- Drop support for Python 3.9 and earlier
2. **RESP3 is default**
```python
# v7.x defaulted to RESP2
# v8.0 defaults to RESP3
r = redis.Redis() # Now RESP3
r = redis.Redis(protocol=2) # Opt into RESP2
```
3. **Async import path changed**
```python
# v7.x
from redis import Redis
client = Redis().asyncio
# v8.0
import redis.asyncio as redis
client = redis.Redis()
```
## References
- [redis-py Official Documentation](https://redis.readthedocs.io/)
- [redis-py v8.0 Release Notes](https://github.com/redis/redis-py/releases)
- [Redis Stack Documentation](https://redis.io/docs/stack/)
- [RESP3 Protocol Specification](https://github.com/antirez/redis-doc/blob/master/RESP3.md)