Redis Key-Pattern Search in DBX: Architecture and Implementation

DBX implements Redis key-pattern search through a layered Tauri-Rust architecture that batches SCAN operations server-side to minimize network round-trips while supporting both standalone and cluster Redis deployments.

The DBX database client (t8y2/dbx) provides efficient Redis key-pattern search capabilities through a sophisticated multi-layered architecture. This implementation leverages Tauri's frontend-backend bridge combined with a Rust-based core library to handle pattern matching, database selection, and batch processing across both direct and clustered Redis connections.

Architecture Overview

DBX implements key-pattern searching across three distinct layers:

  1. Frontend (TypeScript) – UI components invoke Tauri commands through redisScanKeys and redisScanKeysBatch functions
  2. Tauri Command Layer (Rust) – Bridges frontend requests to the core library in src-tauri/src/commands/redis_cmd.rs
  3. Core Library (Rust) – crates/dbx-core handles the actual Redis SCAN operations, connection pooling, and batch iteration logic

This architecture allows DBX to perform complex pattern searches (e.g., user:*) while optionally returning key type metadata and supporting both single-node and clustered Redis deployments.

Frontend TypeScript API

The frontend interface in apps/desktop/src/lib/tauri.ts exposes two distinct scanning modes:

// apps/desktop/src/lib/tauri.ts
export async function redisScanKeys(
  connectionId: string,
  db: number,
  cursor: number,
  pattern: string,
  count: number,
) {
  // Single SCAN iteration - returns one page of results
  return invoke("redis_scan_keys", { connectionId, db, cursor, pattern, count });
}

export async function redisScanKeysBatch(
  connectionId: string,
  db: number,
  cursor: number,
  pattern: string,
  count: number,
  maxIterations: number,
  includeTypes: boolean,
) {
  // Server-side batch processing - multiple SCAN cycles in one call
  return invoke("redis_scan_keys_batch", {
    connectionId,
    db,
    cursor,
    pattern,
    count,
    maxIterations,
    includeTypes,
  });
}

The count parameter controls how many keys Redis returns per SCAN iteration, while maxIterations determines how many cursor steps the backend executes before returning aggregated results to the UI.

Tauri Command Layer

The Tauri commands in src-tauri/src/commands/redis_cmd.rs act as thin wrappers that forward requests to the core library:

// src-tauri/src/commands/redis_cmd.rs
pub async fn redis_scan_keys(
    state: State<'_, Arc<AppState>>,
    connection_id: String,
    db: u32,
    cursor: u64,
    pattern: String,
    count: usize,
) -> Result<RedisScanResult, String> {
    dbx_core::redis_ops::redis_scan_keys_core(
        &state,
        &connection_id,
        db,
        cursor,
        &pattern,
        count,
    )
    .await
}

The batch variant forwards additional parameters for server-side iteration:

pub async fn redis_scan_keys_batch(
    state: State<'_, Arc<AppState>>,
    connection_id: String,
    db: u32,
    cursor: u64,
    pattern: String,
    count: usize,
    max_iterations: usize,
    include_types: bool,
) -> Result<RedisScanResult, String> {
    dbx_core::redis_ops::redis_scan_keys_batch_core(
        &state,
        &connection_id,
        db,
        cursor,
        &pattern,
        count,
        max_iterations,
        include_types,
    )
    .await
}

Both commands are registered in src-tauri/src/lib.rs to expose them to the frontend.

Core Library Implementation

The actual Redis operations reside in crates/dbx-core/src/redis_ops.rs. The redis_scan_keys_core function delegates to the batch implementation with a single iteration:

// crates/dbx-core/src/redis_ops.rs
pub async fn redis_scan_keys_core(
    state: &AppState,
    connection_id: &str,
    db: u32,
    cursor: u64,
    pattern: &str,
    count: usize,
) -> Result<RedisScanResult, String> {
    redis_scan_keys_batch_core(state, connection_id, db, cursor, pattern, count, 1, true).await
}

The batch core performs up to max_iterations SCAN cycles server-side:

pub async fn redis_scan_keys_batch_core(
    state: &AppState,
    connection_id: &str,
    db: u32,
    cursor: u64,
    pattern: &str,
    count: usize,
    max_iterations: usize,
    include_types: bool,
) -> Result<RedisScanResult, String> {
    ensure_redis_pool(state, connection_id).await?;
    let connections = state.connections.read().await;
    let pool = connections.get(connection_id).ok_or("Connection not found")?;

    match pool {
        PoolKind::Redis(redis) => match redis {
            RedisConnection::Direct(con) => {
                let mut con = con.lock().await;
                redis_driver::select_db(&mut *con, db).await?;
                redis_driver::scan_keys_batch(
                    &mut *con,
                    cursor,
                    pattern,
                    count,
                    max_iterations,
                    include_types,
                )
                .await
            }
            RedisConnection::Cluster(cluster) => {
                redis_driver::ensure_cluster_db(db)?;
                // Cluster-specific batch handling...
            }
        },
        _ => Err("Not a Redis connection".to_string()),
    }
}

Handling Direct Connections

For standalone Redis servers, DBX uses RedisConnection::Direct and explicitly selects the database index via redis_driver::select_db. This ensures pattern searches operate against the correct logical database (0-15 in standard Redis configurations).

Handling Cluster Deployments

When connecting to RedisConnection::Cluster, DBX validates the database selection through ensure_cluster_db before executing distributed scans. Since Redis Cluster handles key distribution across nodes, the scan operation automatically traverses the cluster topology while the batch logic accumulates results across multiple cursor iterations.

Batch Processing Benefits

Setting max_iterations > 1 drastically reduces frontend-to-backend round-trips. A naive implementation requesting one cursor page at a time would generate a network request for every SCAN iteration. By batching up to max_iterations cycles on the server side, DBX can fetch hundreds or thousands of keys in a single request, improving latency and reducing load on the Redis server.

Web API Integration

Beyond the desktop application, the same core functions are exposed via HTTP routes in crates/dbx-web/src/routes/redis.rs. This allows external tools, browser extensions, or third-party integrations to utilize identical key-pattern search logic through the DBX web server.

Summary

  • DBX uses a three-tier architecture (TypeScript → Tauri → Rust core) to execute Redis SCAN commands with minimal network overhead
  • Batch mode (max_iterations) processes multiple cursor iterations server-side before returning results to the frontend
  • Dual connection support handles both Direct (standalone) and Cluster Redis configurations with proper database selection
  • Optional type metadata returns Redis key types (string, hash, list, etc.) when include_types is enabled
  • Shared core logic is exposed via both Tauri commands and HTTP routes for maximum flexibility across desktop and web interfaces

Frequently Asked Questions

How does DBX handle large key spaces when scanning?

DBX utilizes the max_iterations parameter in redis_scan_keys_batch_core to perform multiple SCAN cycles on the server side before returning results to the frontend. This approach significantly reduces network round-trips compared to cursor-by-cursor fetching, making it suitable for databases containing millions of keys.

Does DBX support Redis Cluster for pattern searches?

Yes, the core library explicitly handles RedisConnection::Cluster variants in crates/dbx-core/src/redis_ops.rs. For cluster connections, DBX validates database selection through ensure_cluster_db while leveraging Redis Cluster's distributed scan capabilities to search across all nodes in the topology.

What information does DBX return for each matched key?

When the include_types parameter is set to true, DBX returns RedisKeyInfo objects containing the key name, its Redis data type (string, hash, list, set, etc.), and the next cursor position for pagination. This eliminates the need for additional TYPE command round-trips for each matched key.

Can the Redis key-pattern search be used outside the desktop application?

Yes, the identical redis_scan_keys_core functions are exposed via HTTP routes in crates/dbx-web/src/routes/redis.rs. This allows external tools, browser extensions, or automated scripts to utilize the same scanning logic and connection pooling through the DBX web server API.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →