How to Iterate Redis Keys with SCAN in Python

Iterate all Redis keys matching a pattern using the SCAN command with a mock client to simulate pagination.

Easy Python 3.9+ Aug 9, 2026 Caching & Redis 15 views 0 copies

Requires third-party packages — install first
pip install redis

Python code

34 lines
Python 3.9+
import redis

def scan_keys(client, pattern="*", count=10):
    keys = []
    cursor = 0
    while True:
        cursor, batch = client.scan(cursor=cursor, match=pattern, count=count)
        keys.extend(batch)
        if cursor == 0:
            break
    return keys

if __name__ == "__main__":
    # Mock Redis client to simulate SCAN iteration
    class MockRedis:
        def __init__(self):
            self.data = {f"user:{i}" for i in range(100)}
            self.data.update({f"post:{i}" for i in range(50)})
        
        def scan(self, cursor=0, match="*", count=10):
            keys = sorted(self.data)
            total = len(keys)
            start = cursor
            end = min(start + count, total)
            next_cursor = end if end < total else 0
            batch = [k for k in keys[start:end] if k.startswith(match.replace("*", ""))]
            return next_cursor, batch

    mock = MockRedis()
    user_keys = scan_keys(mock, pattern="user:*", count=20)
    post_keys = scan_keys(mock, pattern="post:*", count=20)
    print(f"Users: {len(user_keys)} keys")
    print(f"Posts: {len(post_keys)} keys")
    print(f"Total user keys sample: {sorted(user_keys)[:5]}")

Output

stdout
Users: 100 keys
Posts: 50 keys
Total user keys sample: ['user:0', 'user:1', 'user:10', 'user:11', 'user:12']

How it works

The client.scan method returns a cursor and a batch of keys; you loop until the cursor returns to 0. The count parameter is a hint for the batch size, not a strict limit. This avoids blocking the Redis server like KEYS does. The mock client replicates the cursor behavior with a simple list slice. Sorting keys ensures deterministic output in the mock, but real Redis order is undefined.

Common mistakes

  • Assuming `count` limits total keys returned, not just per-call batch size
  • Forgetting to handle the cursor loop, causing infinite loops or missing keys
  • Using `KEYS` in production, which blocks the server for large key sets

Variations

  1. Use `scan_iter` method which abstracts the cursor loop internally
  2. Add `type` parameter to SCAN to filter by data type (e.g., 'hash')

Real-world use cases

  • Cleaning up stale cache keys matching a prefix like 'session:*' in a maintenance script.
  • Migrating a subset of keys from one Redis instance to another without blocking production traffic.
  • Building a metrics dashboard that counts keys by pattern (e.g., 'user:*') across shards.

Sponsored

Run locally

This sample needs third-party packages, so it cannot run in the browser IDE. Copy the code above, install the packages shown at the top, then run it in your own Python environment.

More from Caching & Redis

Related tutorials and quizzes for this topic.