Skip to main content

Description

Iterates the set of keys in the database using a cursor-based iterator. Unlike KEYS, SCAN doesn’t block the server and is safe to use in production.

Method Signatures

// Basic scan
scan(cursor: string | number): Promise<[string, string[]]>

// Scan with options (standard)
scan(
  cursor: string | number,
  opts: ScanCommandOptionsStandard
): Promise<[string, string[]]>

// Scan with type information
scan(
  cursor: string | number,
  opts: ScanCommandOptionsWithType
): Promise<[string, { key: string; type: string }[]]>

Parameters

cursor
string | number
required
The cursor position. Use "0" or 0 to start a new iteration.
opts
ScanCommandOptions
Optional configuration object:

Return Value

result
[string, string[]] | [string, { key: string; type: string }[]]
A tuple containing:
  1. Next cursor - Use this value in the next scan call. When "0", iteration is complete.
  2. Keys - Array of matching keys (or objects with key and type if withType: true)

Examples

Basic iteration

let cursor = "0";
const allKeys: string[] = [];

do {
  const [nextCursor, keys] = await redis.scan(cursor);
  allKeys.push(...keys);
  cursor = nextCursor;
} while (cursor !== "0");

console.log(allKeys);

Scan with pattern matching

let cursor = "0";
const userKeys: string[] = [];

do {
  const [nextCursor, keys] = await redis.scan(cursor, {
    match: "user:*"
  });
  userKeys.push(...keys);
  cursor = nextCursor;
} while (cursor !== "0");

console.log(userKeys);

Scan with count hint

const [cursor, keys] = await redis.scan("0", {
  count: 100  // Request approximately 100 keys per iteration
});

console.log(`Found ${keys.length} keys, next cursor: ${cursor}`);

Filter by key type

let cursor = "0";
const stringKeys: string[] = [];

do {
  const [nextCursor, keys] = await redis.scan(cursor, {
    type: "string"
  });
  stringKeys.push(...keys);
  cursor = nextCursor;
} while (cursor !== "0");

console.log(stringKeys);

Scan with type information

let cursor = "0";

do {
  const [nextCursor, items] = await redis.scan(cursor, {
    withType: true
  });
  
  items.forEach(({ key, type }) => {
    console.log(`${key} is a ${type}`);
  });
  
  cursor = nextCursor;
} while (cursor !== "0");

Combine options

const [cursor, items] = await redis.scan("0", {
  match: "user:*",
  count: 50,
  withType: true
});

items.forEach(({ key, type }) => {
  console.log(`${key} (${type})`);
});

Single-pass scan

// Get first batch of keys
const [cursor, keys] = await redis.scan("0");
console.log(keys);

// If cursor is "0", we've seen all keys
// Otherwise, there are more keys to fetch
if (cursor !== "0") {
  console.log("More keys available");
}

Cursor-Based Iteration

The SCAN command uses cursor-based iteration:
  1. Start with cursor "0"
  2. Call scan(cursor) and receive [nextCursor, keys]
  3. Process the keys
  4. If nextCursor is "0", iteration is complete
  5. Otherwise, call scan(nextCursor) and repeat
The cursor is opaque - don’t parse or manipulate it. Always use the cursor returned from the previous call.

Guarantees and Characteristics

  • Full iteration guarantee: A key that exists from start to finish will be returned
  • No duplicates guarantee: A key that is never modified will be returned only once
  • Safe for production: Non-blocking, suitable for large databases
  • Variable results: The number of keys returned per call may vary
  • Pattern matching: Filtering happens after fetching, so you may get empty results

See Also

  • keys - Get all keys matching a pattern (blocking)
  • type - Get the type of a key