
Why KRaft Mode Matters
Direct answer: For local Kafka development in 2026, use a single Kafka broker in KRaft mode plus Kafka UI. The critical setting is KAFKA_ADVERTISED_LISTENERS; if it points at the wrong host or port, clients will connect once and then fail on broker metadata.
Kafka Raft Metadata (KRaft) is a new mode for Apache Kafka that eliminates the need for Zookeeper. It was introduced in KIP-500 to remove the kafka dependency on Zookeeper. Apache Kafka traditionally required Zookeeper for cluster coordination - until KRaft (Kafka Raft Metadata) mode arrived. This update eliminates Zookeeper dependencies while improving:

Image from Kafka Raft Metadata (KRaft) mode
- Simplified architecture: Fewer moving parts
- Faster recovery: Metadata changes happen in milliseconds
- Easier scaling: More predictable cluster behavior
I recently wanted to setup Kafka for my local development, and after quite a few tries, ngl, I was finally able to do it. Let’s show you how it went.
This guide focuses on the local broker loop. If you are also tightening deployment fundamentals, see the Next.js self-hosting guide and the Go Docker image optimization guide for the same container-first production mindset.
Prerequisites
- Docker (Latest version?)
- 4GB+ free memory (Kafka containers can be hungry)
Complete Docker Compose Setup
services:
kafka:
image: apache/kafka:latest
container_name: broker
environment:
KAFKA_NODE_ID: 1
KAFKA_PROCESS_ROLES: broker,controller
KAFKA_LISTENERS: PLAINTEXT://:9092,CONTROLLER://:9093,EXTERNAL://:9094
KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://broker:9092,EXTERNAL://localhost:9094
KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT,EXTERNAL:PLAINTEXT
KAFKA_CONTROLLER_QUORUM_VOTERS: 1@broker:9093
KAFKA_CONTROLLER_LISTENER_NAMES: CONTROLLER
KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR: 1
KAFKA_TRANSACTION_STATE_LOG_MIN_ISR: 1
ports:
- "9094:9094"
healthcheck:
test:
[
"CMD-SHELL",
"./opt/kafka/bin/kafka-broker-api-versions.sh --bootstrap-server localhost:9092 > /dev/null 2>&1",
]
interval: 10s
timeout: 10s
retries: 5
kafka-ui:
image: provectuslabs/kafka-ui:latest
container_name: kafka-ui
ports:
- "8088:8080"
environment:
KAFKA_CLUSTERS_0_NAME: local
KAFKA_CLUSTERS_0_BOOTSTRAPSERVERS: broker:9092
KAFKA_CLUSTERS_0_READONLY: "false"
depends_on:
kafka:
condition: service_healthyKafka Configuration:
KAFKA_NODE_ID: Unique identifier for the brokerKAFKA_PROCESS_ROLES: Broker and controller rolesKAFKA_LISTENERS: Listeners for different protocolsKAFKA_ADVERTISED_LISTENERS: Addresses advertised to clientsKAFKA_LISTENER_SECURITY_PROTOCOL_MAP: Security protocol mapKAFKA_INTER_BROKER_LISTENER_NAME: Inter-broker listener nameKAFKA_CONTROLLER_QUORUM_VOTERS: Controller quorum votersKAFKA_CONTROLLER_LISTENER_NAMES: Controller listener namesKAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: Offsets topic replication factorKAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR: Transaction state log replication factorKAFKA_TRANSACTION_STATE_LOG_MIN_ISR: Transaction state log minimum ISR
Cluster Management Commands
Start all services:
docker-compose up -dVerify running containers:
docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"Expected output:
NAMES STATUS PORTS
broker Up 4 minutes (healthy) 9092/tcp, 0.0.0.0:9094->9094/tcp
kafka-ui Up 4 minutes 0.0.0.0:8088->8080/tcpMonitoring with Kafka UI
After starting containers, access http://localhost:8088 to:
- View real-time broker status
- Inspect topic configurations
- Monitor consumer lag
- Explore message payloads
- Manage ACLs (access control lists)
Connection URLs to use in your applications
You will need to connect to the broker using the following URL:
- If running outside of docker:
localhost:9094- If running inside of docker:
broker:9092Topic Management: CLI vs UI
Command-line creation:
docker exec broker /opt/kafka/bin/kafka-topics.sh \
--topic orders \
--create \
--bootstrap-server localhost:9092 \
--partitions 3 \
--replication-factor 1UI alternative:
- Navigate to Topics → Create Topic
- Set partitions/replication
- Click “Submit”

Message Production Patterns
Basic text messages:
docker exec -it broker /opt/kafka/bin/kafka-console-producer.sh \
--topic orders \
--bootstrap-server localhost:9092
Structured JSON:
# Using jq for JSON formatting
echo '{"id":1001, "amount":49.99}' | jq -c | docker exec -i broker /opt/kafka/bin/kafka-console-producer.sh \
--topic orders \
--bootstrap-server localhost:9092
You can also see the messages on the UI:

Troubleshooting Checklist
Brokers not connecting?
- Check port conflicts with
netstat -tuln | grep 9092
UI not showing topics?
- Ensure bootstrap servers match in UI config
- Check container logs:
docker logs kafka-ui
When to Choose This Setup
Good for:
- Local development
- CI/CD pipelines
- Prototyping new features
Not for:
- Production deployments
- High-availability requirements
- Sensitive data handling
Learn More
Related Articles
Deploy Next.js Without Vercel: Self-Hosting Production Guide
Deploy a Next.js app without Vercel using standalone output, Docker, and a production-ready Node server that can run on any VM, container host, or cloud.
dockerBest Dockerfile for Golang, Optimize Your Dockerfile
Create best Dockerfile for Golang, optimize your Dockerfile for Golang and make it blazingly fast! 🔥