{
  "schema_version": 2,
  "id": "commands/hotkeys",
  "title": "HOTKEYS",
  "url": "https://redis.io/docs/latest/commands/hotkeys/",
  "summary": "A container for hotkeys tracking commands.",
  "since": "8.6.0",
  "tags": [
    "docs",
    "develop",
    "stack",
    "oss",
    "rs",
    "rc",
    "oss",
    "kubernetes",
    "clients"
  ],
  "last_updated": "2026-10-12T10:32:09+01:00",
  "page_type": "content",
  "content_hash": "336f4fb044d3c2d6624a7191b977541b9b984213cf0ab09925c9f32296743354",
  "sections": [
    {
      "id": "usage",
      "title": "Usage",
      "role": "syntax",
      "text": "The general workflow is for the user to initiate a hotkeys tracking process which should run for some time. The keys' metrics are recorded inside a probabilistic data structure, after which the user is able to fetch the top K metrics.\n\nAvailable subcommands:\n\n- [`HOTKEYS START`](https://redis.io/docs/latest/commands/hotkeys-start) - Starts hotkeys tracking with specified metrics.\n- [`HOTKEYS STOP`](https://redis.io/docs/latest/commands/hotkeys-stop) - Stops hotkeys tracking but preserves data.\n- [`HOTKEYS GET`](https://redis.io/docs/latest/commands/hotkeys-get) - Returns tracking results and metadata.\n- [`HOTKEYS RESET`](https://redis.io/docs/latest/commands/hotkeys-reset) - Releases resources used for tracking."
    },
    {
      "id": "example",
      "title": "Example",
      "role": "example",
      "text": "The following example tracks keys by CPU time and network bytes, reads the results while tracking is active, and then stops tracking and releases its resources.\n\nThe redis-py and go-redis cluster clients, and redis-rs async cluster connections, don't support `HOTKEYS`. With these clients, connect directly to a single node instead.\n\nProfiling: Find the keys that use the most CPU time and network bandwidth using HOTKEYS START, GET, STOP, and RESET (only one tracking session can run at a time)\n\n**Difficulty:** Intermediate\n\n**Commands:** HOTKEYS, GET, HOTKEYS RESET\n\n**Complexity:**\n- HOTKEYS: Depends on subcommand\n- GET: O(1)\n- HOTKEYS RESET: O(1)\n\n**Available in:** Redis CLI, C#, Go, Java, Java (Asynchronous - Lettuce), Java (Reactive - Lettuce), Java (Synchronous - Jedis), JavaScript (Node.js), PHP, Python, Rust (Asynchronous), Rust (Synchronous)\n\n##### Redis CLI\n\n[code example]\n\n##### C#\n\n[code example]\n\n##### Go\n\n[code example]\n\n##### Java\n\n[code example]\n\n##### Java (Asynchronous - Lettuce)\n\n[code example]\n\n##### Java (Reactive - Lettuce)\n\n[code example]\n\n##### Java (Synchronous - Jedis)\n\n[code example]\n\n##### JavaScript (Node.js)\n\n[code example]\n\n##### PHP\n\n[code example]\n\n##### Python\n\n[code example]\n\n##### Rust (Asynchronous)\n\n[code example]\n\n##### Rust (Synchronous)\n\n[code example]"
    }
  ],
  "examples": [
    {
      "id": "example-ex0",
      "language": "plaintext",
      "code": "> HOTKEYS START METRICS 2 CPU NET COUNT 10\nOK\n> GET product:1\n\"Laptop\"\n> GET product:1\n\"Laptop\"\n> GET product:2\n\"Phone\"\n> HOTKEYS GET\n1)  1) \"tracking-active\"\n    2) (integer) 1\n    3) \"sample-ratio\"\n    4) (integer) 1\n    5) \"selected-slots\"\n    6) 1) 1) (integer) 0\n          2) (integer) 16383\n    7) \"all-commands-all-slots-us\"\n    8) (integer) 27\n    9) \"net-bytes-all-commands-all-slots\"\n   10) (integer) 119\n   11) \"collection-start-time-unix-ms\"\n   12) (integer) 1791553768375\n   13) \"collection-duration-ms\"\n   14) (integer) 44\n   15) \"total-cpu-time-user-ms\"\n   16) (integer) 2\n   17) \"total-cpu-time-sys-ms\"\n   18) (integer) 0\n   19) \"total-net-bytes\"\n   20) (integer) 119\n   21) \"by-cpu-time-us\"\n   22) 1) \"product:1\"\n       2) (integer) 24\n       3) \"product:2\"\n       4) (integer) 3\n   23) \"by-net-bytes\"\n   24) 1) \"product:1\"\n       2) (integer) 80\n       3) \"product:2\"\n       4) (integer) 39\n> HOTKEYS STOP\nOK\n> HOTKEYS RESET\nOK",
      "section_id": "example"
    },
    {
      "id": "example-ex1",
      "language": "csharp",
      "code": "// Track the 10 hottest keys by CPU time and network bytes.\n        server.HotKeysStart(metrics: HotKeysMetrics.Cpu | HotKeysMetrics.Network, count: 10);\n\n        // Generate some traffic. In production, this is your application's workload.\n        for (int i = 0; i < 100; i++)\n        {\n            db.StringGet(\"product:1\");\n        }\n\n        for (int i = 0; i < 10; i++)\n        {\n            db.StringGet(\"product:2\");\n        }\n\n        db.StringGet(\"product:3\");\n\n        HotKeysResult res2 = server.HotKeysGet();\n        Console.WriteLine(res2.TrackingActive); // >>> True\n\n        var byNet = res2.NetworkBytesByKey.ToArray();\n        Console.WriteLine(string.Join(\", \", byNet.Select(k => $\"{k.Key}: {k.Bytes}\")));\n        // >>> product:1: 4000, product:2: 390, product:3: 40\n\n        bool res3 = server.HotKeysStop();\n        Console.WriteLine(res3); // >>> True\n\n        server.HotKeysReset();",
      "section_id": "example"
    },
    {
      "id": "example-ex2",
      "language": "go",
      "code": "// Track the 10 hottest keys by CPU time and network bytes.\n\tres1, err := rdb.HotKeysStart(ctx, &redis.HotKeysStartArgs{\n\t\tMetrics: []redis.HotKeysMetric{redis.HotKeysMetricCPU, redis.HotKeysMetricNET},\n\t\tCount:   10,\n\t}).Result()\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfmt.Println(res1) // >>> OK\n\n\t// Generate some traffic. In production, this is your application's workload.\n\tfor i := 0; i < 100; i++ {\n\t\trdb.Get(ctx, \"product:1\")\n\t}\n\n\tfor i := 0; i < 10; i++ {\n\t\trdb.Get(ctx, \"product:2\")\n\t}\n\n\trdb.Get(ctx, \"product:3\")\n\n\tres2, err := rdb.HotKeysGet(ctx).Result()\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfmt.Println(res2.TrackingActive) // >>> true\n\n\tfmt.Println(res2.ByNetBytes)\n\t// >>> [{product:1 4000} {product:2 390} {product:3 40}]\n\n\tres3, err := rdb.HotKeysStop(ctx).Result()\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfmt.Println(res3) // >>> OK\n\n\tres4, err := rdb.HotKeysReset(ctx).Result()\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfmt.Println(res4) // >>> OK",
      "section_id": "example"
    },
    {
      "id": "example-ex3",
      "language": "java",
      "code": "// Track the 10 hottest keys by CPU time and network bytes.\n            String res1 = syncCommands.hotkeysStart(\n                    HotkeysArgs.Builder.metrics(HotkeysArgs.Metric.CPU, HotkeysArgs.Metric.NET).count(10));\n            System.out.println(res1); // >>> OK\n\n            // Generate some traffic. In production, this is your application's workload.\n            for (int i = 0; i < 100; i++) {\n                syncCommands.get(\"product:1\");\n            }\n\n            for (int i = 0; i < 10; i++) {\n                syncCommands.get(\"product:2\");\n            }\n\n            syncCommands.get(\"product:3\");\n\n            HotkeysReply res2 = syncCommands.hotkeysGet();\n            System.out.println(res2.isTrackingActive()); // >>> true\n\n            Map<String, Long> byNet = res2.getByNetBytes();\n            System.out.println(byNet);\n            // >>> {product:1=4000, product:2=390, product:3=40}\n\n\n            String res3 = syncCommands.hotkeysStop();\n            System.out.println(res3); // >>> OK\n\n            String res4 = syncCommands.hotkeysReset();\n            System.out.println(res4); // >>> OK",
      "section_id": "example"
    },
    {
      "id": "example-ex4",
      "language": "java",
      "code": "// Track the 10 hottest keys by CPU time and network bytes.\n            CompletableFuture<Void> hotkeysExample = asyncCommands.hotkeysStart(\n                    HotkeysArgs.Builder.metrics(HotkeysArgs.Metric.CPU, HotkeysArgs.Metric.NET).count(10))\n                    .thenCompose(res1 -> {\n                        System.out.println(res1); // >>> OK\n\n                        // Generate some traffic. In production, this is your application's workload.\n                        List<CompletableFuture<String>> traffic = new ArrayList<>();\n                        for (int i = 0; i < 100; i++) {\n                            traffic.add(asyncCommands.get(\"product:1\").toCompletableFuture());\n                        }\n\n                        for (int i = 0; i < 10; i++) {\n                            traffic.add(asyncCommands.get(\"product:2\").toCompletableFuture());\n                        }\n\n                        traffic.add(asyncCommands.get(\"product:3\").toCompletableFuture());\n\n                        return CompletableFuture.allOf(traffic.toArray(new CompletableFuture[0]));\n                    })\n                    .thenCompose(v -> asyncCommands.hotkeysGet())\n                    .thenCompose(res2 -> {\n                        System.out.println(res2.isTrackingActive()); // >>> true\n\n                        System.out.println(res2.getByNetBytes());\n                        // >>> {product:1=4000, product:2=390, product:3=40}\n\n\n                        return asyncCommands.hotkeysStop();\n                    })\n                    .thenCompose(res3 -> {\n                        System.out.println(res3); // >>> OK\n\n                        return asyncCommands.hotkeysReset();\n                    })\n                    .thenAccept(res4 -> {\n                        System.out.println(res4); // >>> OK\n                    })\n                    .toCompletableFuture();\n\n            hotkeysExample.join();",
      "section_id": "example"
    },
    {
      "id": "example-ex5",
      "language": "java",
      "code": "// Track the 10 hottest keys by CPU time and network bytes.\n            Mono<Void> hotkeysExample = reactiveCommands.hotkeysStart(\n                    HotkeysArgs.Builder.metrics(HotkeysArgs.Metric.CPU, HotkeysArgs.Metric.NET).count(10))\n                    .doOnNext(res1 -> {\n                        System.out.println(res1); // >>> OK\n                    })\n                    // Generate some traffic. In production, this is your application's workload.\n                    .thenMany(Flux.range(0, 100).flatMap(i -> reactiveCommands.get(\"product:1\")))\n                    .thenMany(Flux.range(0, 10).flatMap(i -> reactiveCommands.get(\"product:2\")))\n                    .then(reactiveCommands.get(\"product:3\"))\n                    .then(reactiveCommands.hotkeysGet())\n                    .doOnNext(res2 -> {\n                        System.out.println(res2.isTrackingActive()); // >>> true\n\n                        System.out.println(res2.getByNetBytes());\n                        // >>> {product:1=4000, product:2=390, product:3=40}\n\n                    })\n                    .then(reactiveCommands.hotkeysStop())\n                    .doOnNext(res3 -> {\n                        System.out.println(res3); // >>> OK\n                    })\n                    .then(reactiveCommands.hotkeysReset())\n                    .doOnNext(res4 -> {\n                        System.out.println(res4); // >>> OK\n                    })\n                    .then();\n\n            hotkeysExample.block();",
      "section_id": "example"
    },
    {
      "id": "example-ex6",
      "language": "java",
      "code": "// Track the 10 hottest keys by CPU time and network bytes.\n        String res1 = jedis.hotkeysStart(\n            HotkeysParams.hotkeysParams()\n                .metrics(HotkeysMetric.CPU, HotkeysMetric.NET)\n                .count(10)\n        );\n        System.out.println(res1); // >>> OK\n\n        // Generate some traffic. In production, this is your application's workload.\n        for (int i = 0; i < 100; i++) {\n            jedis.get(\"product:1\");\n        }\n\n        for (int i = 0; i < 10; i++) {\n            jedis.get(\"product:2\");\n        }\n\n        jedis.get(\"product:3\");\n\n        HotkeysInfo res2 = jedis.hotkeysGet();\n        System.out.println(res2.isTrackingActive()); // >>> true\n\n        Map<String, Long> byNet = res2.getByNetBytes();\n        System.out.println(byNet);\n        // >>> {product:1=4000, product:2=390, product:3=40}\n\n        String res3 = jedis.hotkeysStop();\n        System.out.println(res3); // >>> OK\n\n        String res4 = jedis.hotkeysReset();\n        System.out.println(res4); // >>> OK",
      "section_id": "example"
    },
    {
      "id": "example-ex7",
      "language": "javascript",
      "code": "// Track the 10 hottest keys by CPU time and network bytes.\nconst res1 = await client.hotkeysStart({\n    METRICS: { count: 2, CPU: true, NET: true },\n    COUNT: 10\n});\nconsole.log(res1); // >>> OK\n\n// Generate some traffic. In production, this is your application's workload.\nfor (let i = 0; i < 100; i++) {\n    await client.get('product:1');\n}\n\nfor (let i = 0; i < 10; i++) {\n    await client.get('product:2');\n}\n\nawait client.get('product:3');\n\nconst res2 = await client.hotkeysGet();\nconsole.log(res2.trackingActive); // >>> 1\n\nconst byNet = res2.byNetBytes.map(({ key, value }) => [key, value]);\nconsole.log(byNet);\n// >>> [ [ 'product:1', 4000 ], [ 'product:2', 390 ], [ 'product:3', 40 ] ]\n\nconst res3 = await client.hotkeysStop();\nconsole.log(res3); // >>> OK\n\nconst res4 = await client.hotkeysReset();\nconsole.log(res4); // >>> OK",
      "section_id": "example"
    },
    {
      "id": "example-ex8",
      "language": "php",
      "code": "// Track the 10 hottest keys by CPU time and network bytes.\n        $res1 = $r->hotkeys->start([\\Predis\\Command\\Container\\HOTKEYS::CPU, \\Predis\\Command\\Container\\HOTKEYS::NET], 10);\n        echo $res1 . PHP_EOL; // >>> OK\n\n        // Generate some traffic. In production, this is your application's workload.\n        for ($i = 0; $i < 100; $i++) {\n            $r->get('product:1');\n        }\n\n        for ($i = 0; $i < 10; $i++) {\n            $r->get('product:2');\n        }\n\n        $r->get('product:3');\n\n        $res2 = $r->hotkeys->get()[0];\n        echo $res2['tracking-active'] . PHP_EOL; // >>> 1\n\n        $byNet = $res2['by-net-bytes'];\n        echo json_encode(array_chunk($byNet, 2)) . PHP_EOL;\n        // >>> [[\"product:1\",4000],[\"product:2\",390],[\"product:3\",40]]\n\n        $res3 = $r->hotkeys->stop();\n        echo $res3 . PHP_EOL; // >>> OK\n\n        $res4 = $r->hotkeys->reset();\n        echo $res4 . PHP_EOL; // >>> OK",
      "section_id": "example"
    },
    {
      "id": "example-ex9",
      "language": "python",
      "code": "from redis.commands.core import HotkeysMetricsTypes\n\n# Track the 10 hottest keys by CPU time and network bytes.\nres1 = r.hotkeys_start(\n    metrics=[HotkeysMetricsTypes.CPU, HotkeysMetricsTypes.NET], count=10\n)\nprint(res1)  # >>> OK\n\n# Generate some traffic. In production, this is your application's workload.\nfor _ in range(100):\n    r.get(\"product:1\")\n\nfor _ in range(10):\n    r.get(\"product:2\")\n\nr.get(\"product:3\")\n\nres2 = r.hotkeys_get()[0]\nprint(res2[\"tracking-active\"])  # >>> 1\n\nby_net = res2[\"by-net-bytes\"]\nprint(list(zip(by_net[::2], by_net[1::2])))\n# >>> [('product:1', 4000), ('product:2', 390), ('product:3', 40)]\n\nres3 = r.hotkeys_stop()\nprint(res3)  # >>> OK\n\nres4 = r.hotkeys_reset()\nprint(res4)  # >>> OK",
      "section_id": "example"
    },
    {
      "id": "example-ex10",
      "language": "rust",
      "code": "// Track the 10 hottest keys by CPU time and network bytes.\n        let opts = HotkeysOptions::new_with_cpu()\n            .and_net()\n            .with_count(10)\n            .expect(\"COUNT must be between 1 and 64\");\n\n        match r.hotkeys_start(opts).await {\n            Ok(res1) => {\n                println!(\"{res1:?}\"); // >>> ()\n            }\n            Err(e) => println!(\"Error starting hotkeys tracking: {e}\"),\n        }\n\n        // Generate some traffic. In production, this is your application's workload.\n        for _ in 0..100 {\n            let _: Result<String, _> = r.get(\"product:1\").await;\n        }\n\n        for _ in 0..10 {\n            let _: Result<String, _> = r.get(\"product:2\").await;\n        }\n\n        let _: Result<String, _> = r.get(\"product:3\").await;\n\n        match r.hotkeys_get().await {\n            Ok(Some(res2)) => {\n                println!(\"{}\", res2.tracking_active); // >>> true\n\n                let by_net: Vec<(&str, u64)> = res2\n                    .by_net_bytes\n                    .iter()\n                    .flatten()\n                    .map(|entry| (entry.key.as_str(), entry.value))\n                    .collect();\n                println!(\"{by_net:?}\");\n                // >>> [(\"product:1\", 4000), (\"product:2\", 390), (\"product:3\", 40)]\n            }\n            Ok(None) => {\n                println!(\"No hotkeys tracking session\");\n            }\n            Err(e) => println!(\"Error getting hotkeys: {e}\"),\n        }\n\n        match r.hotkeys_stop().await {\n            Ok(res3) => {\n                println!(\"{res3}\"); // >>> true\n            }\n            Err(e) => println!(\"Error stopping hotkeys tracking: {e}\"),\n        }\n\n        match r.hotkeys_reset().await {\n            Ok(res4) => {\n                println!(\"{res4:?}\"); // >>> ()\n            }\n            Err(e) => println!(\"Error resetting hotkeys: {e}\"),\n        }",
      "section_id": "example"
    },
    {
      "id": "example-ex11",
      "language": "rust",
      "code": "// Track the 10 hottest keys by CPU time and network bytes.\n        let opts = HotkeysOptions::new_with_cpu()\n            .and_net()\n            .with_count(10)\n            .expect(\"COUNT must be between 1 and 64\");\n\n        match r.hotkeys_start(opts) {\n            Ok(res1) => {\n                println!(\"{res1:?}\"); // >>> ()\n            }\n            Err(e) => println!(\"Error starting hotkeys tracking: {e}\"),\n        }\n\n        // Generate some traffic. In production, this is your application's workload.\n        for _ in 0..100 {\n            let _: Result<String, _> = r.get(\"product:1\");\n        }\n\n        for _ in 0..10 {\n            let _: Result<String, _> = r.get(\"product:2\");\n        }\n\n        let _: Result<String, _> = r.get(\"product:3\");\n\n        match r.hotkeys_get() {\n            Ok(Some(res2)) => {\n                println!(\"{}\", res2.tracking_active); // >>> true\n\n                let by_net: Vec<(&str, u64)> = res2\n                    .by_net_bytes\n                    .iter()\n                    .flatten()\n                    .map(|entry| (entry.key.as_str(), entry.value))\n                    .collect();\n                println!(\"{by_net:?}\");\n                // >>> [(\"product:1\", 4000), (\"product:2\", 390), (\"product:3\", 40)]\n            }\n            Ok(None) => {\n                println!(\"No hotkeys tracking session\");\n            }\n            Err(e) => println!(\"Error getting hotkeys: {e}\"),\n        }\n\n        match r.hotkeys_stop() {\n            Ok(res3) => {\n                println!(\"{res3}\"); // >>> true\n            }\n            Err(e) => println!(\"Error stopping hotkeys tracking: {e}\"),\n        }\n\n        match r.hotkeys_reset() {\n            Ok(res4) => {\n                println!(\"{res4:?}\"); // >>> ()\n            }\n            Err(e) => println!(\"Error resetting hotkeys: {e}\"),\n        }",
      "section_id": "example"
    }
  ]
}
