← all projects

project details

Kafkaesque

A focused Kafka monitoring dashboard, API, and CLI for understanding a cluster before it becomes a production incident.

Kafkaesque monitoring dashboard for Apache Kafka clusters
GoApache KafkaHTMXPostgreSQL 18+DockerSlack

#overview

Monitoring Kafka is essential, but the standard command-line tools are best suited to one-off checks and broad observability platforms can require more infrastructure than a team needs. Kafkaesque provides a focused, read-only interface where developers and operators can understand a cluster without producing messages or changing Kafka resources.

The responsive web UI brings connection status, cluster health, brokers, topics, hourly message rates, consumer groups, and partition lag into one place. Teams can create Slack alerts with configurable average or maximum lag thresholds, receive one notification when a threshold is breached, and optionally receive a follow-up when the lag resolves.

The same Go application also exposes an authenticated JSON API and a standalone CLI. Kafka connections support plaintext, TLS, mutual TLS, SASL PLAIN, and SASL SCRAM. PostgreSQL is reserved for application accounts, sessions, roles, permissions, migrations, and alert subscriptions. It never stores Kafka messages or historical cluster metrics.

#how it works

Browser and API requests enter the same Kafkaesque server process. The UI uses secure session cookies, API clients use opaque access and refresh tokens, and both pass through PostgreSQL-backed authentication and role-based access control before reaching shared live Kafka collectors. The UI is server-rendered with HTMX and still supports filtering and pagination as ordinary links and forms when JavaScript is unavailable.

The collectors read metadata, consumer groups, offsets, and assignments directly from Kafka. Separate monitors reuse those collectors to calculate hourly topic activity and evaluate lag-alert subscriptions, then deliver firing and resolved notifications to Slack. The standalone CLI bypasses PostgreSQL and connects directly to Kafka for text, JSON, and watch-mode inspection.

Kafkaesque remains deliberately read-only: it does not create topics, alter cluster resources, produce or browse messages, or store Kafka payloads. The server ships as one Go binary with embedded UI assets, runs as a non-root container, and applies versioned PostgreSQL migrations during startup.

#features

ConcernDetails
Web monitoring
  • Dashboard for connection status, cluster totals, and health
  • Broker, topic, partition, and consumer-group inspection
  • Hourly topic message rates and partition-level consumer lag
  • Responsive server-rendered UI with configurable refresh intervals
Kafka connectivity
  • Plaintext, TLS, and mutual TLS connections
  • SASL PLAIN, SCRAM-SHA-256, and SCRAM-SHA-512 authentication
  • Broker address overrides for containers, Kubernetes, and split networks
Authentication and access
  • PostgreSQL-backed users, sessions, built-in roles, and custom RBAC
  • Secure browser cookies with CSRF protection
  • Opaque API access and refresh tokens
Slack lag alerts
  • Average or maximum partition-lag thresholds
  • Slack Incoming Webhook and Workflow Builder trigger support
  • One firing notification per breach with an optional resolution notification
API and CLI
  • Authenticated JSON API for Kafka inspection
  • Text or JSON CLI output with in-place watch mode
  • Direct CLI inspection without PostgreSQL or an application account
Deployment
  • One Go binary with embedded UI assets and no Node.js runtime
  • Non-root Linux containers for AMD64 and ARM64
  • Versioned PostgreSQL migrations applied during server startup

#run the web UI with Docker

Kafkaesque publishes a multi-platform container containing the API and embedded web UI. The container runs kafkaesque serve as a non-root user and listens on port 8085 by default.

Before you start

  1. Kafka bootstrap addresses that the container can reach, including the broker, coordinator, and partition-leader addresses returned by Kafka.
  2. A dedicated PostgreSQL 18 or newer database and a role allowed to create and modify objects in its public schema.
  3. A Super Admin username, email address, and policy-compliant password.
  4. A stable encryption key used to protect Slack webhook URLs.

01Generate the alert encryption key and pull the image

Generate this key once and keep it in a secret manager. Pull latest for a local trial. Production deployments should pin an exact release tag or image digest.

Generate a 32-byte key

openssl rand -base64 32

Pull Kafkaesque

docker pull ghcr.io/nikhil25803/kafkaesque:latest

02Option A: mount a YAML configuration

Create config.yaml, replace every CHANGE_ME value, and mount the file read-only. Use a Docker network hostname, host.docker.internal where supported, or another address reachable from inside the container. Localhost points back to the container itself.

config.yaml

kafka:
  bootstrap_server: kafka.example.com:9092

authentication:
  super_admin_username: super_admin
  super_admin_email: super-admin@example.com
  super_admin_password: CHANGE_ME_A1_
  super_admin_recovery: verify
  cookie_secure: false

database:
  url: postgres://kafkaesque:CHANGE_ME@postgres.example.com:5432/kafkaesque?sslmode=require

alerts:
  encryption_key: CHANGE_ME_WITH_OPENSSL_OUTPUT

api:
  host: 0.0.0.0
  port: 8085

Start with the mounted file

docker run --rm --name kafkaesque \
  --publish 8085:8085 \
  --volume "$PWD/config.yaml:/config.yaml:ro" \
  ghcr.io/nikhil25803/kafkaesque:latest \
  serve --config /config.yaml

03Option B: configure with environment variables

Every server setting also has an environment-variable form. This is convenient when a deployment platform injects secrets without a mounted configuration file.

Start with environment variables

docker run --rm --name kafkaesque \
  --publish 8085:8085 \
  --env KAFKAESQUE_KAFKA_BOOTSTRAP_SERVER=kafka.example.com:9092 \
  --env KAFKAESQUE_AUTHENTICATION_SUPER_ADMIN_USERNAME=super_admin \
  --env KAFKAESQUE_AUTHENTICATION_SUPER_ADMIN_EMAIL=super-admin@example.com \
  --env KAFKAESQUE_AUTHENTICATION_SUPER_ADMIN_PASSWORD=CHANGE_ME_A1_ \
  --env KAFKAESQUE_AUTHENTICATION_SUPER_ADMIN_RECOVERY=verify \
  --env KAFKAESQUE_AUTHENTICATION_COOKIE_SECURE=false \
  --env 'KAFKAESQUE_DATABASE_URL=postgres://kafkaesque:CHANGE_ME@postgres.example.com:5432/kafkaesque?sslmode=require' \
  --env KAFKAESQUE_ALERTS_ENCRYPTION_KEY=CHANGE_ME_WITH_OPENSSL_OUTPUT \
  --env KAFKAESQUE_API_HOST=0.0.0.0 \
  --env KAFKAESQUE_API_PORT=8085 \
  ghcr.io/nikhil25803/kafkaesque:latest serve

04Verify the process and sign in

The health endpoint verifies that the server process is responding. Then open the UI and sign in with the configured Super Admin account.

Health check

curl --fail http://127.0.0.1:8085/api/v1/health

Web UI

http://127.0.0.1:8085/ui

#UI walkthrough

Dashboard and cluster monitoring

Operational pages read Kafka at request time, providing a current view without maintaining a stale cluster cache.

Kafkaesque dashboard showing connection status, cluster totals, consumer groups, and cluster health

Dashboard

The landing page confirms the active Kafka connection and summarizes brokers, topics, partitions, and consumer groups. Health cards surface unhealthy partitions and lagging consumers immediately, giving operators a fast starting point before opening a detailed view.

Kafkaesque consumer groups list with search, state filtering, and lag status

Consumer Groups

Consumer groups can be searched and filtered by coordinator state or lag health. Each row combines group state, active membership, topic coverage, and aggregate lag so an idle, rebalancing, or falling-behind workload stands out before drilling into partition assignments.

Kafkaesque topics list showing topic levels, partitions, replication, and hourly message rates

Topics

The topics view separates internal and application topics and reports partition count, replication, and hourly activity. Search and pagination keep large clusters manageable, while message-rate changes help distinguish quiet topics from active data paths.

Kafkaesque brokers list showing advertised addresses, effective connection addresses, and racks

Brokers

Broker inspection shows IDs, rack placement, advertised listeners, and the effective addresses Kafkaesque uses. Displaying both advertised and overridden addresses makes container, Kubernetes, and split-network connection problems easier to diagnose.

Kafkaesque cluster health page showing cluster, partition, and consumer diagnostics

Cluster Health

Cluster Health brings broker availability, leaderless or under-replicated partitions, offline replicas, and consumer lag thresholds together. Healthy, warning, and unhealthy states use the configured lag thresholds so the same policy is reflected across the UI, API, and alerts.

Access and settings

PostgreSQL-backed accounts and roles protect the browser and API while every authenticated role retains read-only Kafka inspection access.

Kafkaesque sign-in page with account credentials and product branding

Sign in

Browser users authenticate through a focused sign-in screen and receive secure session cookies protected against cross-site request forgery. The initial Super Admin comes from server configuration. Additional accounts can sign in immediately after creation.

Kafkaesque user settings showing account details, assigned roles, and pagination

Settings · Users

Authorized administrators can search and page through accounts, review assigned roles, and manage access without touching Kafka. User records, password hashes, sessions, and role assignments remain isolated in the dedicated PostgreSQL database.

Kafkaesque role settings showing system roles, permissions, and assigned users

Settings · Roles

The role list exposes built-in Super Admin, Admin, and User roles alongside custom roles. Permission summaries and assigned-user counts make it clear who can manage accounts, roles, and alert subscriptions while Kafka access stays read-only.

Kafkaesque add-user form with identity, password, and role fields

Add User

The account form captures identity, a policy-compliant initial password, and one or more roles in a single workflow. Validation is shared with authentication so newly created users can sign in without a separate activation step.

Kafkaesque create-role form with account, role, and alert permissions

Create Role

Custom roles group only the administrative capabilities a team needs. Account, role, and alert-management permissions can be selected independently, supporting least-privilege operational access without introducing Kafka write permissions.

Slack alert lifecycle

Lag subscriptions turn consumer health thresholds into actionable Slack notifications without repeatedly notifying for the same incident.

Kafkaesque Slack alert subscription settings with status and threshold information

Slack Alerts

The subscriptions page lists each monitored consumer group, optional topic filter, lag calculation, threshold, delivery method, and current state. Operators can quickly distinguish enabled monitors from paused or currently firing subscriptions.

Kafkaesque form for creating a Slack consumer-lag alert

Create Slack Alert

A subscription can monitor average or maximum partition lag for an entire consumer group or a selected topic. It supports Slack Incoming Webhooks and Workflow Builder triggers, configurable polling, and an optional resolution message when lag returns below the threshold.

Slack notification showing a fired Kafkaesque consumer-lag alert

Lag Alert Fired

When lag crosses the configured threshold, Kafkaesque sends one firing notification with the consumer group, topic scope, observed lag, threshold, and timestamp. It records the firing state so repeated monitor cycles do not flood the channel.

Slack notification showing a resolved Kafkaesque consumer-lag alert

Lag Alert Resolved

After the measured lag recovers, an optional resolution notification closes the loop with the current lag and incident duration. The subscription then returns to its ready state and can report a future breach as a new incident.

view source on GitHub