Need to list all the keys in your Redis database? If you're debugging an issue or just checking what's stored, retrieving all keys is a useful skill for any developer.
This guide covers everything you need to know—from the basic commands to the performance implications—so you can query Redis efficiently without slowing things down.
What is Redis and Why Do Keys Matter?
Redis is an in-memory data structure store used as a database, cache, message broker, and streaming engine. Think of it as your application's high-speed sidekick - blazing fast but with a different approach to data management than traditional databases.
Keys in Redis are the gateway to your data. Each piece of information stored in Redis has a key that you use to access it. Understanding how to work with these keys is essential for effective Redis management.
Basic Command to Get All Keys in Redis
The most straightforward way to get all keys in Redis is with the KEYS
command:
KEYS *
That's it. This command returns all keys matching the pattern provided (in this case, the wildcard *
matches everything).
Here's what it looks like in action:
127.0.0.1:6379> KEYS *
1) "user:1000"
2) "product:34891"
3) "session:abc123"
4) "counter:visits"
Simple enough, right? But before you start using this command everywhere, let's talk about why using KEYS
it might not always be your best move.
Why You Shouldn't Use KEYS in Production
The KEYS
command is easy to use, but it comes with a major catch - it's a blocking operation that scans the entire keyspace. In plain English: it can freeze your Redis server while it runs.
Here's why that's bad news:
- In large databases,
KEYS
can take seconds or even minutes to complete - During this time, Redis stops processing other commands
- Your application might time out waiting for responses
- Users start wondering why your app suddenly feels like it's running on a 90s modem
This isn't just theoretical. I've seen production incidents triggered by a single KEYS
command run during peak hours. Not a fun situation to explain to your boss.
A Better Way to Get All Redis Keys
The KEYS
command is often used to fetch all keys in Redis, but it's not ideal for large datasets because it retrieves everything at once, potentially blocking the server.
A better approach is the SCAN
command, which fetches keys incrementally.
Using SCAN Instead of KEYS
Example: Using SCAN
SCAN 0 MATCH * COUNT 100
This command:
- Returns a batch of keys (default is 100, but Redis may adjust dynamically).
- Provides a cursor value that helps paginate results.
- Continues fetching keys until the cursor returns to
0
.
Sample Execution in Redis CLI:
127.0.0.1:6379> SCAN 0 MATCH * COUNT 100
1) "163"
2) 1) "user:1000"
2) "product:34891"
127.0.0.1:6379> SCAN 163 MATCH * COUNT 100
1) "0"
2) 1) "session:abc123"
2) "counter:visits"
Since the second command returns a cursor of "0", we know we've retrieved all keys.
journalctl
can help you track down issues.How to Implement SCAN in Different Languages
Python Implementation
import redis
def get_all_keys(redis_client):
keys = []
cursor = 0
while True:
cursor, batch = redis_client.scan(cursor, match='*', count=100)
keys.extend(batch)
if cursor == 0:
break
return keys
# Usage
r = redis.Redis(host='localhost', port=6379)
all_keys = get_all_keys(r)
print(f"Found {len(all_keys)} keys")
Explanation:
- Initializes an empty list to store keys.
- Iterates through Redis using SCAN with a cursor.
- Retrieves keys in batches of 100 and stops when the cursor returns to
0
.
Node.js Implementation
const Redis = require('ioredis');
async function getAllKeys(redisClient) {
const keys = [];
let cursor = '0';
do {
const [nextCursor, batch] = await redisClient.scan(cursor, 'MATCH', '*', 'COUNT', 100);
cursor = nextCursor;
keys.push(...batch);
} while (cursor !== '0');
return keys;
}
// Usage
const redis = new Redis();
getAllKeys(redis).then(keys => {
console.log(`Found ${keys.length} keys`);
});
Explanation:
- Uses
ioredis
to interact with Redis. - Fetches keys in batches using
SCAN
. - Iterates through the results asynchronously until all keys are retrieved.
How to Filter Keys with Patterns
Often, you don't need all keys, just a subset matching a certain pattern. Redis supports wildcard matching:
*
matches any sequence of characters.?
matches any single character.[abc]
matches any single character inside the brackets.[^abc]
matches any single character NOT in the brackets.
Examples:
# Get all user-related keys
SCAN 0 MATCH user:* COUNT 100
# Get all session keys from a specific date
SCAN 0 MATCH session:2025-03-04:* COUNT 100
# Get all cache keys with numeric IDs
SCAN 0 MATCH cache:[0-9]* COUNT 100
How to Find Keys by Data Type
Sometimes, you need to filter keys based on their data type (e.g., string, list, set). While Redis doesn’t provide a direct command for this, we can use a combination of SCAN
and TYPE
.
Shell Script to Get Keys by Type:
# Get all keys and filter by type
redis-cli --scan --pattern '*' | while read key; do
type=$(redis-cli type "$key")
if [ "$type" = "string" ]; then
echo "$key"
fi
done
Explanation:
- Scans for all keys.
- Uses
redis-cli type
to check each key’s type. - Prints only keys that match a specified type (in this case,
string
).
This approach can be modified for other data types like list
, hash
, set
, etc.
Performance Tips for Working with Keys in Large Redis Databases
When dealing with Redis at scale, these tips will help keep things running smoothly:
1. Schedule Key Operations During Low-Traffic Periods
If you need to run commands that operate on large numbers of keys, schedule them during off-peak hours when your system can better handle the load.
2. Use Key Naming Conventions
A good naming strategy makes key management easier:
service:entity:id:field
For example:
user:profile:1000:email
product:inventory:34891:count
This approach creates natural namespaces that you can easily filter with pattern matching.
3. Set Appropriate TTLs
Not all data needs to live forever. Setting expiration times (TTLs) on keys helps Redis automatically clean up stale data:
SET session:user:1000 "session_data" EX 3600 # expires in 1 hour
4. Monitor Your Keyspace Size
Keep an eye on your total key count with the INFO keyspace
command:
127.0.0.1:6379> INFO keyspace
# Keyspace
db0:keys=1234,expires=632,avg_ttl=57983
Redis Memory Optimization When Dealing with Many Keys
Each key in Redis consumes memory - not just for the value, but for the key itself and associated metadata. Here's how to keep memory usage in check:
Shorter Key Names Save Memory
While descriptive keys are nice, they consume memory. Consider:
# 49 bytes
user:profile:1000:preferences:theme:color
# 15 bytes
u:1000:p:t:c
In a database with millions of keys, this difference adds up quickly.
Use Hashes for Related Data
Instead of storing related data as separate keys:
user:1000:name "John"
user:1000:email "john@example.com"
user:1000:age 32
Use a hash to group them:
HSET user:1000 name "John" email "john@example.com" age 32
This dramatically reduces the number of keys and overall memory usage.
Practical Use Cases for Getting All Keys
Let's explore some common scenarios where you might need to retrieve all keys:
Data Migration Between Redis Instances
When moving data between Redis servers, you need to know what to transfer:
# Script outline for Redis migration
source_redis = redis.Redis(host='old-server', port=6379)
target_redis = redis.Redis(host='new-server', port=6379)
# Get all keys from source
keys = get_all_keys(source_redis)
# For each key, copy to target
for key in keys:
# Get key type
key_type = source_redis.type(key)
# Handle different data types appropriately
if key_type == b'string':
target_redis.set(key, source_redis.get(key))
elif key_type == b'hash':
target_redis.hset(key, mapping=source_redis.hgetall(key))
# Handle other types...
Explanation:
- Connects to the source and target Redis servers.
- Retrieves all keys from the source server.
- Copies each key to the target server, handling different data types appropriately.
Debugging Cache Issues
When troubleshooting cache problems, examining keys can help identify patterns:
import redis
from collections import Counter
r = redis.Redis()
keys = get_all_keys(r)
# Analyze key prefixes
prefixes = [k.split(':')[0] for k in keys]
prefix_counts = Counter(prefixes)
print("Key namespace distribution:")
for prefix, count in prefix_counts.most_common():
print(f"{prefix}: {count} keys")
Explanation:
- Fetches all Redis keys and extracts their prefixes.
- Counts occurrences of each prefix using
Counter
. - Prints a breakdown of key distributions to detect anomalies.
Handling Redis Keys in a Cluster Environment
Redis Cluster distributes keys across multiple nodes, requiring a different approach to key retrieval.
from rediscluster import RedisCluster
def get_all_cluster_keys(cluster_client):
all_keys = []
# Get all master nodes
nodes = [node for node in cluster_client.get_nodes() if not node.is_replica]
# For each node, perform SCAN
for node in nodes:
node_client = node.redis_connection
cursor = 0
while True:
cursor, keys = node_client.scan(cursor, match='*', count=100)
all_keys.extend(keys)
if cursor == 0:
break
return all_keys
# Usage
startup_nodes = [{"host": "127.0.0.1", "port": "7000"}]
rc = RedisCluster(startup_nodes=startup_nodes)
keys = get_all_cluster_keys(rc)
Explanation:
- Identifies master nodes in the Redis Cluster.
- Iterates through each node, performing
SCAN
to fetch keys. - Aggregates keys from all master nodes to get a complete list.
Using the right approach for your Redis setup ensures efficient key retrieval without impacting performance.
Monitoring and Limiting Key Growth
Every Redis database needs boundaries. Here's how to monitor and control key growth:
Track Key Creation Rate
Set up monitoring to track the rate of key creation. A sudden spike could indicate an issue like missing TTLs or a runaway process.
Implement a Key Budget Per Service
Establish quotas for how many keys each service can create. This prevents one misbehaving service from crowding out others.
Understand Redis's maxmemory Policy
When Redis reaches its memory limit, its behavior depends on the maxmemory-policy
setting:
# Check current policy
CONFIG GET maxmemory-policy
# Common settings:
# noeviction - Return errors when memory is full
# allkeys-lru - Evict least recently used keys
# volatile-lru - Evict least recently used keys with TTL
Choose a policy that matches your use case - generally volatile-lru
provides a good balance.
Redis Transactions When Operating on Multiple Keys
When you need to perform operations on multiple keys as a single atomic unit, use Redis transactions:
MULTI
GET user:1000:balance
GET user:1001:balance
SET user:1000:balance 400
SET user:1001:balance 600
EXEC
All commands between MULTI
and EXEC
are executed as a single atomic operation, ensuring data consistency.
A Quick Reference to Redis CLI Commands
Here's a quick reference for common Redis CLI commands related to keys:
Command | Description | Example |
---|---|---|
KEYS pattern | Get all keys matching pattern (avoid in production) | KEYS user:* |
SCAN cursor [MATCH pattern] [COUNT count] | Incrementally scan for keys | SCAN 0 MATCH session:* COUNT 100 |
TYPE key | Get the type of a key | TYPE user:1000 |
TTL key | Get remaining time to live of a key | TTL session:abc123 |
EXPIRE key seconds | Set a key's time to live in seconds | EXPIRE cache:results 300 |
DEL key [key ...] | Delete one or more keys | DEL user:1000 user:1001 |
EXISTS key [key ...] | Check if key(s) exist | EXISTS login:token:xyz |
RANDOMKEY | Get a random key from the database | RANDOMKEY |
FAQs
Can I safely use the KEYS command in my scripts?
No, the KEYS command should never be used in production environments or automated scripts. It's a blocking operation that scans the entire keyspace, which can cause performance issues and downtime. Always use SCAN for production use cases.
How can I count the total number of keys in Redis without retrieving them all?
You can use the DBSIZE
command, which returns the number of keys in the current database without scanning the entire keyspace:
127.0.0.1:6379> DBSIZE
(integer) 1234
This command is much faster than KEYS or SCAN when you only need the count.
How do I find the biggest keys in my Redis database?
Redis doesn't have a built-in command to find the largest keys, but you can use the redis-cli tool with the --bigkeys option:
redis-cli --bigkeys
This scans your keyspace and reports the biggest keys of each data type, helping you identify memory hogs.
Is there a way to get all keys without pattern matching?
Yes, using SCAN
with the default pattern (which is none) will return all keys:
SCAN 0 COUNT 100
This is equivalent to SCAN 0 MATCH * COUNT 100
but slightly more efficient since it doesn't perform pattern matching.
What happens if I delete a key while using SCAN?
SCAN provides a guarantee that every key present throughout a complete iteration will be returned at least once. If you delete keys during the scan, they won't be returned in later iterations. If you add keys during the scan, they may or may not be returned, depending on their hash values.
How do I get keys from a specific Redis database?
Redis supports multiple logical databases (numbered from 0 to 15 by default). To get keys from a specific database, you need to select that database first:
SELECT 2 # Switch to database 2
SCAN 0 MATCH * COUNT 100 # Now scanning database 2
Remember that each database has its own keyspace.
Can I get all keys with a specific TTL range?
Redis doesn't provide a direct way to query keys by TTL range. You'd need to:
- Get all keys with SCAN
- Check the TTL of each key with the TTL command
- Filter based on your criteria
Here's a simple Bash script that does this:
redis-cli --scan | while read key; do
ttl=$(redis-cli ttl "$key")
# Print keys that expire within an hour (TTL < 3600 and TTL > 0)
if [ "$ttl" -lt 3600 ] && [ "$ttl" -gt 0 ]; then
echo "$key expires in $ttl seconds"
fi
done