Prasenjit Vijay Hiwale

kaffy

A terminal UI for exploring and operating Kafka clusters. Follow messages live, jump to any offset or time, read Avro and Protobuf through your Schema Registry, keep an eye on consumer lag, and manage schemas and topics. For Linux and macOS.

curl -fsSL https://prasenjithiwale.github.io/folio/kaffy/install.sh | sh

Latest release v0.1.0, . Linux (x86_64, arm64) and macOS. Other ways to install · Source on GitHub

 ◆ kaffy  demo  ✎ WRITE  ● connected · 3 brokers  topic orders     1 Topics   2 Groups   3 Schemas   4 Brokers  
╭ orders ───────── 3 partitions · from last 100 per partition · 313 buffered (max 5000) · 313 received  ● LIVE ╮
│     P  OFFSET  TIMESTAMP                KEY       VALUE                                                      │
│     1     397  2026-10-15 15:14:58.480  cust-067  {"order_id":"ord-1-000397","customer":"cust-067","status": │
│     2     397  2026-10-15 15:14:58.480  cust-109  {"order_id":"ord-2-000397","customer":"cust-109","status": │
│     0     398  2026-10-15 15:14:59.980  cust-062  {"order_id":"ord-0-000398","customer":"cust-062","status": │
│     1     398  2026-10-15 15:14:59.980  cust-222  {"order_id":"ord-1-000398","customer":"cust-222","status": │
│     2     398  2026-10-15 15:14:59.980  cust-007  {"order_id":"ord-2-000398","customer":"cust-007","status": │
│     0     399  2026-10-15 15:15:01.480  cust-221  ∅ tombstone                                                │
│     1     399  2026-10-15 15:15:01.480  cust-070  ∅ tombstone                                                │
│     2     399  2026-10-15 15:15:01.480  cust-025  ∅ tombstone                                                │
│     1     400  2026-10-15 15:15:03.273  cust-225  {"order_id":"ord-1-000400","customer":"cust-225","status": │
│     0     400  2026-10-15 15:15:03.393  cust-235  {"order_id":"ord-0-000400","customer":"cust-235","status": │
│     1     401  2026-10-15 15:15:03.514  cust-053  {"order_id":"ord-1-000401","customer":"cust-053","status": │
│     2     400  2026-10-15 15:15:03.635  cust-064  {"order_id":"ord-2-000400","customer":"cust-064","status": │
│     1     402  2026-10-15 15:15:03.754  cust-021  {"order_id":"ord-1-000402","customer":"cust-021","status": │
│     0     401  2026-10-15 15:15:03.875  cust-224  {"order_id":"ord-0-000401","customer":"cust-224","status": │
│     2     401  2026-10-15 15:15:03.995  cust-077  {"order_id":"ord-2-000401","customer":"cust-077","status": │
│     1     403  2026-10-15 15:15:04.114  cust-091  {"order_id":"ord-1-000403","customer":"cust-091","status": │
│     1     404  2026-10-15 15:15:04.234  cust-024  {"order_id":"ord-1-000404","customer":"cust-024","status": │
│     0     402  2026-10-15 15:15:04.355  cust-122  {"order_id":"ord-0-000402","customer":"cust-122","status": │
│     1     405  2026-10-15 15:15:04.475  cust-129  {"order_id":"ord-1-000405","customer":"cust-129","status": │
│     1     406  2026-10-15 15:15:04.595  cust-040  {"order_id":"ord-1-000406","customer":"cust-040","status": │
│ ▌   0     403  2026-10-15 15:15:04.714  cust-210  {"order_id":"ord-0-000403","customer":"cust-210","status": │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
 ↑↓  move   ⏎  open   space  pause   /  filter   p  produce   E  edit & produce   :  commands   ?  keys         

Opening a topic shows the last 100 messages of each partition, then follows new ones as they arrive.

See it run

Recorded in kaffy --demo: open a topic from the command palette, filter it to paid or shipped orders on two partitions, read one message, check a stopped consumer group's growing lag, preview an offset reset without applying it, and diff two versions of an Avro schema. Also available as a GIF.

Tested at scale

kaffy 0.5 was timed on a cluster with 2,000+ topics, 6,000+ partitions, 5.3 million messages, over 1,000 consumer groups and 200 live consumers, twice: on one broker on the same machine, and on three brokers reached over SASL_SSL through a 30 ms round trip, like a cluster in the cloud. A script drove kaffy and timed what appeared on screen.

kaffy 0.5.0 on the same data
Local broker3 brokers, SASL_SSL, 30 ms away
Topic list0.30 s0.66 s
All 1,000+ consumer groups with lag0.23 s0.83 s
One group's lag per partition0.07 s0.18 s
A page of history from offset 0 (1M-message topic)0.07 s0.47 s
The next page0.50 s0.53 s
Memory, groups tab open31 MB31 MB
Threads / open sockets18 / 2119 / 27
CPU, groups tab open3.3 %2.5 %

Lag matched Kafka's own kafka-consumer-groups exactly. On shared clusters, show only what you work on with topics = ["checkout-*"] and groups = [...] in a profile, or --topics and --groups for one run.

Compared with 0.4.1

These tests found that 0.4.1 didn't scale: on the local broker it never showed the 1,050-group list (still empty after 400 s), used about 9 cores, 3,440 threads and 6,685 sockets, and jumped to the newest messages instead of the start of a big topic. 0.5.0 fixes all of it. The release notes have the details.

Time to see the full list of 1,050 consumer groups: 0.4.1 never showed it within 400 seconds, 0.5.0 took 0.23 seconds. Threads in the first minute with the groups tab open: 0.4.1 climbs past 1,700, 0.5.0 stays at 18. CPU in the first minute with the groups tab open: 0.4.1 rises to about 900 percent, 0.5.0 stays near zero. Reading a 1M-message topic from the start: peak memory 292 MB on 0.4.1 and 75 MB on 0.5.0; average CPU 17.3 percent and 2.6 percent.

Measured on a MacBook (Apple Silicon, 10 cores) running the brokers too. The 30 ms delay is fixed, with no loss or jitter; a real network varies more. Not yet tested: tens of thousands of partitions, and Confluent Cloud or MSK themselves. The numbers are in metrics.json.

Install

The install script picks the build for your system, downloads the latest release, checks its SHA-256 checksum and puts kaffy in ~/.local/bin. It works with sh and bash, on Linux and macOS.

curl -fsSL https://prasenjithiwale.github.io/folio/kaffy/install.sh | sh

Homebrew

On macOS or Linux, install from the prasenjithiwale/tap tap. Homebrew loads formulae from other people's taps only once you trust them, which is the first command:

brew trust --formula prasenjithiwale/tap/kaffy && brew install prasenjithiwale/tap/kaffy

Then brew upgrade kaffy picks up new releases.

Options

Set these before sh to change what the script does:

curl -fsSL https://prasenjithiwale.github.io/folio/kaffy/install.sh | KAFFY_VERSION=v0.5.0 KAFFY_INSTALL_DIR=/usr/local/bin sh
KAFFY_VERSION
Install a specific release instead of the latest.
KAFFY_INSTALL_DIR
Where to put the binary. Defaults to ~/.local/bin; a system directory may need sudo sh.

Requirements

Linux on x86_64 or arm64, any distribution: the binary is static, so Alpine and older systems work too. macOS 11 or newer, on Apple Silicon or Intel.

Manual download

Download the archive for your system and compare it with its SHA-256 checksum:

    The first release is being published. Check back in a few minutes.

    Uninstall

    Delete the binary: rm ~/.local/bin/kaffy, or brew uninstall kaffy if Homebrew installed it. kaffy keeps its config in ~/.config/kaffy and its log in ~/.cache/kaffy.

    Get started

    Try it without Kafka

    kaffy --demo runs against a built-in fake cluster with live data, including Avro messages, a small Schema Registry and topic configs.

    Connect to a broker

    kaffy --bootstrap localhost:9092 connects without any setup. Add --schema-registry http://localhost:8081 to decode Avro, JSON Schema and Protobuf.

    Save your clusters

    Describe clusters in ~/.config/kaffy/config.toml, then pick one with kaffy --profile staging. Profiles support SSL, mutual TLS and SASL (PLAIN, SCRAM), and read passwords from environment variables rather than the file.

    [profiles.staging]
    bootstrap_servers = "broker-1.staging:9094"
    security_protocol = "sasl_ssl"
    sasl = { mechanism = "SCRAM-SHA-512", username = "svc-kaffy", password_env = "KAFFY_STAGING_PASSWORD" }
    schema_registry = { url = "https://schema-registry.staging:8081" }

    Cloud clusters

    Confluent Cloud works with an API key over SASL/PLAIN. Amazon MSK with IAM access control needs only the region; kaffy signs the tokens with your AWS credentials, including SSO and assumed roles through the AWS CLI:

    [profiles.msk]
    bootstrap_servers = "b-1.mycluster.abc123.c2.kafka.eu-west-1.amazonaws.com:9098"
    security_protocol = "sasl_ssl"
    aws_msk_iam = { region = "eu-west-1", profile = "msk-dev" }

    Protobuf without a registry

    For topics carrying plain Protobuf, point a profile at the .proto files. kaffy compiles them itself, so protoc isn't needed.

    [[profiles.staging.protobuf]]
    topic = "orders-proto"
    files = ["proto/orders.proto"]
    include = ["proto"]
    value = "acme.Order"

    Only your topics and groups

    On a shared cluster, a profile can list what to show. Patterns use * and ?, and a leading ! leaves names out. --topics and --groups do the same for one run. This narrows the view; use Kafka ACLs to restrict access.

    [profiles.staging]
    topics = ["checkout-*", "payments", "!*.dlq"]
    groups = ["checkout-*"]

    Using kaffy

    Keys on the messages screen, and the other screens
    /Filter messages
    spacePause or resume the live tail, or read the next page of history
    b eRead from the beginning a page at a time, or follow only new messages
    o tJump to an offset, or to a time such as -15m
    enterOpen a message
    y YCopy the value or key
    p EProduce a message, or edit this one and produce it
    KProduce a tombstone for this key
    XReplay messages into a topic
    xExport the shown messages
    1Topics, where c shows the config, n creates a topic, D deletes one and T deletes records
    2Consumer groups, where R resets offsets
    4Brokers and partition health
    :Command palette: run a command or jump to a topic, group or subject
    3Schemas, where d diffs versions, e edits and n registers a new subject
    ?All keys of the current screen
    escGo back

    Make it yours

    kaffy has dark and light themes, and uses your terminal's 16 colors where true color isn't available. Pick one with --theme or theme = "light" in the config. Any key can be rebound in a [keys] table, and the help and footer show your keys:

    [keys]
    pause = "p"
    produce = "P"

    Filter examples

    cust-042
    Key or value contains the text, ignoring case.
    ~"status":"(PAID|SHIPPED)"
    Key or value matches a regular expression.
    key:cust- h:trace-id
    Search only the key, value (value:) or headers.
    p:0,2 after:-1h
    Partitions 0 and 2, from the last hour. before: works too.
    !cancelled
    Leave out matching messages.

    Making changes

    Every change shows exactly what will happen and waits for y. On profiles marked prod = true you type the group or topic name instead. Profiles are read-only unless you set read_only = false, and kaffy never joins a consumer group just to read, so browsing moves no one's offsets.

    Reset offsets
    Move a stopped consumer group to the earliest or latest offset, a point in time, or a specific offset, on all its topics or one. The preview shows how many messages will be processed again or skipped.
    Produce
    Write a message in your $EDITOR: key, headers, partition and value. Editing an Avro message keeps it Avro.
    Replay
    Copy a range of messages, by offset or time, into the same or another topic. The current filter applies, so you can replay only the messages you are looking at.
    Schemas
    Edit the latest schema of a subject in your $EDITOR, or start a new Avro, JSON Schema or Protobuf subject. kaffy checks compatibility with the registry, shows the diff, and registers only when you confirm.
    Topics
    Create and delete topics, and change their configs. kaffy reads the config back to confirm a change took effect.
    Delete records
    Remove everything before an offset or a time. Like deleting a topic, this can't be undone, so it always asks you to type the topic name, on every profile.
    Tombstones
    Produce a null value for a message's key, which deletes the key on compacted topics.
    Export
    Save the shown messages as JSON, NDJSON or CSV. Works on read-only profiles too.

    Try all of it safely with kaffy --demo, whose fake cluster accepts changes.