Kafka Protocol
Surgewave implements ~93% of the Kafka 4.0 wire protocol and tracks Kafka 4.2.
Compatibility
The authoritative, per-RPC and per-KIP status table — including which RPCs
are wired, which reject with structured errors, and which are intentionally
out of scope — lives under Conformance in this docs site
(canonical source: CONFORMANCE.md
at the repository root). It is generated from the same
ApiVersionsResponse.CreateDefault source and per-handler
SupportedApiKeys lists used at runtime.
Quick highlights:
| API Key | API Name | Version Range |
|---|---|---|
| 0 | Produce | 0-13 |
| 1 | Fetch | 4-18 |
| 2 | ListOffsets | 1-11 |
| 3 | Metadata | 0-13 |
| 8 | OffsetCommit | 2-10 |
| 9 | OffsetFetch | 1-10 |
| 10 | FindCoordinator | 0-6 |
| 11 | JoinGroup | 0-9 |
| 12 | Heartbeat | 0-4 |
| 13 | LeaveGroup | 0-5 |
| 14 | SyncGroup | 0-5 |
| 18 | ApiVersions | 0-5 |
| 19 | CreateTopics | 2-7 |
| 20 | DeleteTopics | 1-6 |
| 68 | ConsumerGroupHeartbeat (KIP-848) | 0-1 |
| 76 | ShareGroupHeartbeat (KIP-932) | 1 |
| 88 | StreamsGroupHeartbeat (KIP-1071) | 0 |
For the full matrix and the complete KIP coverage list, see Conformance / Kafka API matrix and Conformance / KIP coverage.
Using Kafka Clients
Confluent.Kafka (.NET)
var config = new ProducerConfig
{
BootstrapServers = "localhost:9092"
};
using var producer = new ProducerBuilder<string, string>(config).Build();
await producer.ProduceAsync("my-topic", new Message<string, string>
{
Key = "key",
Value = "value"
});
librdkafka (C/C++)
rd_kafka_conf_t *conf = rd_kafka_conf_new();
rd_kafka_conf_set(conf, "bootstrap.servers", "localhost:9092", NULL, 0);
rd_kafka_t *producer = rd_kafka_new(RD_KAFKA_PRODUCER, conf, NULL, 0);
kafka-python
from kafka import KafkaProducer
producer = KafkaProducer(bootstrap_servers='localhost:9092')
producer.send('my-topic', b'message')
kafka-go
conn, _ := kafka.DialLeader(context.Background(), "tcp", "localhost:9092", "my-topic", 0)
conn.WriteMessages(kafka.Message{Value: []byte("message")})
Protocol Features
Topic IDs (UUID)
Fetch/Produce v13+ use TopicId instead of topic name:
TopicId: 550e8400-e29b-41d4-a716-446655440000
Flexible Versions
Protocol v2+ supports tagged fields:
- Produce v9+
- Fetch v12+
- Metadata v9+
Compression
| Codec | Type | Support |
|---|---|---|
| None | 0 | Yes |
| GZIP | 1 | Yes |
| Snappy | 2 | Yes |
| LZ4 | 3 | Yes |
| ZSTD | 4 | Yes |
New Consumer Protocol (KIP-848)
OffsetCommit/OffsetFetch v9-10:
- MemberId field
- MemberEpoch field
Wire Format
The first 12 bytes of every Kafka frame are fixed; everything from byte 12 onwards is variable-length and version-dependent.
---
title: "Kafka request/response frame (fixed header + variable tail)"
---
packet-beta
0-3: "Length (int32 BE)"
4-5: "API Key (int16 BE)"
6-7: "API Version (int16 BE)"
8-11: "Correlation ID (int32 BE)"
12-23: "Client ID (string: int16 length + UTF-8 bytes)"
24-27: "[Tagged Fields] (flexible versions only)"
28-31: "Payload (API-specific)"
Note: only the first 12 bytes are at fixed offsets. Client ID,
tagged-fields, and the payload occupy variable byte ranges — the diagram
shows their order on the wire, not exact widths.
Troubleshooting
Version Mismatch
Error: Unsupported API version
Check client version compatibility:
surgewave broker info
Connection Issues
# Test connectivity
nc -zv localhost 9092
# Check broker logs
surgewave diagnose
Configuration
{
"Surgewave": {
"Port": 9092,
"MaxRequestSize": 104857600,
"SocketSendBufferBytes": 102400,
"SocketReceiveBufferBytes": 102400
}
}
Next Steps
- Native Protocol - Higher performance
- Clients - Client library usage