Kafka's ordering model is simple to state, easy to misunderstand, and full of footguns that only show up under load. The short version: Kafka guarantees order within a single partition. It does not guarantee order across partitions, across topics, or globally. Every "I lost ordering in Kafka" incident traces back to one of those nuances, and a handful of producer settings can silently break the per-partition guarantee too.
The Core Guarantee
For a single partition, Kafka guarantees:
- The order in which a producer successfully sends messages to a partition is the order in which they appear in the partition's log.
- The order in which a consumer reads messages from a partition is the same as the order in the log.
- Each message gets a strictly increasing offset within its partition.
That's it. Across partitions, no guarantees. The same is true across topics or across producers.
Partition 0: [A][B][C][D] <- A, B, C, D guaranteed in this order
Partition 1: [E][F][G][H] <- E, F, G, H guaranteed in this order
No relationship between A and E.
Why Cross-Partition Ordering Doesn't Exist
Cross-partition ordering would require global coordination on every produce. That coordination is exactly what Kafka deliberately avoids in order to scale horizontally - each partition is an independent log, processed independently. If you want global ordering, you want a topic with one partition, which means single-threaded throughput.
Most use cases don't actually need global ordering. They need per-entity ordering - all events for user 123 in the order they happened, all updates to order #456 in the order they happened. That's what keys are for.
Preserving Order with Keys
When a producer sends a message with a key, the default partitioner hashes the key and uses the hash modulo partition count to pick a partition. Same key → same partition → guaranteed order.
// All events for user-123 land on the same partition, in order
producer.send(new ProducerRecord<>("events", "user-123", payload));
This gives you the property most applications actually want: ordered processing per entity, parallel processing across entities. The caveat: this only holds as long as the number of partitions doesn't change. If you add partitions, keys re-hash to different partitions, and per-key ordering breaks across the boundary. Plan partition count carefully or use a custom partitioner that's stable.
Settings That Can Silently Break Per-Partition Ordering
Even within a partition, ordering depends on producer settings.
max.in.flight.requests.per.connection
By default, the producer can have multiple in-flight produce requests per broker connection. If request 1 fails and gets retried, but request 2 succeeded first, the messages on the broker end up in the wrong order.
- With
enable.idempotence=true(default in Kafka 3.x), the broker deduplicates and reorders, so up to 5 in-flight requests are safe. - With
enable.idempotence=false, you needmax.in.flight.requests.per.connection=1to preserve order under retries.
If you disabled idempotence to "improve throughput" or "fix a bug," you may have silently broken ordering. Check it.
retries and delivery.timeout.ms
Retries are fine with idempotence. Without it, every retry is a chance to reorder. If you've set retries=0, you trade ordering safety for higher loss risk; if you've set acks=1 with retries, you can both lose messages and reorder.
The combination that gives you ordering and durability:
acks=all
enable.idempotence=true
max.in.flight.requests.per.connection<=5
retries=<some-high-number> (default Integer.MAX_VALUE since Kafka 2.1)
This is the default in modern clients. Don't change these unless you know exactly why.
Custom partitioners
A custom partitioner that picks partitions based on anything but the key (e.g., round-robin, time-based) breaks per-key ordering by definition. Use only for cases where you don't need it.
Consumer-Side Ordering
The consumer reads messages from each assigned partition in offset order. That part is automatic. What you have to be careful about:
- Multi-threading after
poll(). If you hand off messages from one partition to a thread pool, ordering is gone unless you partition the thread pool by key. This is the single most common way applications lose ordering they thought Kafka was giving them. - Rebalances during processing. If a consumer is processing messages and the group rebalances, partitions get reassigned. The new owner starts from the last committed offset, which may be behind. Without idempotent processing, this looks like out-of-order or duplicated processing.
max.poll.recordsand processing latency. If processing one batch takes longer thanmax.poll.interval.ms, the consumer is kicked out of the group mid-batch. Same problem as a rebalance.
The pattern for ordered consumption: one consumer thread per partition, or a thread pool keyed by partition (not by message). Commit offsets only after processing is durable.
Transactional and EOS Ordering
Kafka's exactly-once semantics (EOS) extend the ordering guarantee:
- Messages within a transaction are read in order across all partitions the transaction touched.
- Aborted transactions are invisible to consumers configured with
isolation.level=read_committed.
This is the strongest ordering Kafka offers and is what Kafka Streams uses for stateful processing. It comes at a latency cost (transaction commit adds round-trips), so use it where correctness matters more than peak throughput.
What Doesn't Work
Some patterns that look like they preserve global order but don't:
- "I'll add a timestamp and sort in the consumer." Wall-clock timestamps drift across producers; logical clocks across partitions are essentially impossible to maintain without coordination. Sort by partition+offset within a partition; anything else is an approximation.
- "I'll round-robin across partitions and reconstruct order." Whatever you reconstruct will be approximate, and the moment one partition has higher lag than another, your "order" reflects consumption order, not production order.
- "I'll use a single partition for ordering and many for throughput." That single partition becomes a bottleneck; if you have to split traffic to it, you've reinvented multi-partition routing without the safety.
If you genuinely need global ordering at any scale, Kafka is not the right tool. Use a single-writer system or a transactional database.
Monitoring Ordering Health
You can't directly measure "ordering is preserved," but you can monitor the conditions that break it:
- Producer retries - non-zero retries with idempotence off are a red flag.
record-send-error-rate- errors that drive retries.- Consumer rebalances - frequent rebalances cause re-reads and apparent reordering downstream.
- Consumer lag asymmetry - if one partition is far behind others, downstream merging looks "out of order."
Pulse tracks producer retry rates, consumer rebalance storms, lag asymmetry, and partition leader changes across your Kafka clusters, surfacing the conditions that silently break ordering before they cause an incident. Start a free trial to see what your cluster actually guarantees.
Frequently Asked Questions
Q: Does Kafka guarantee global ordering across all partitions?
A: No. Kafka guarantees ordering within a single partition only. The only way to get global ordering in Kafka is to use a topic with one partition, which caps your throughput at single-threaded levels.
Q: How do I guarantee per-user ordering?
A: Use the user ID as the message key. The default partitioner hashes the key and routes to a specific partition, so all messages for the same user land in the same partition and are processed in order. Avoid adding partitions to a topic where you rely on this - keys re-hash and ordering breaks across the change.
Q: Why are my Kafka messages out of order if I'm using keys?
A: The most likely cause is producer retries with idempotence disabled and max.in.flight.requests.per.connection > 1. Enable idempotence (it's the default in modern clients) or set in-flight requests to 1. The second most common cause is multi-threading on the consumer side - if you process messages from one partition across multiple threads, you've broken the order Kafka gave you.
Q: Does acks=all guarantee ordering?
A: No. acks=all guarantees durability, not ordering. Ordering depends on producer retry behavior, idempotence, and in-flight request count.
Q: Does idempotent producer guarantee ordering?
A: Yes, within a single partition, even with retries and multiple in-flight requests. The broker rejects out-of-order sequence numbers from the producer and the client retries them correctly. Idempotence is enabled by default in Kafka 3.0+.
Q: How does Kafka Streams maintain ordering?
A: Kafka Streams pins each input partition to a single processing task and processes records within a partition strictly in order. For stateful joins and aggregations, it uses repartitioning - sending records to internal topics keyed correctly to preserve per-key order downstream. The EOS mode wraps this in transactions for stronger guarantees.
Q: Can I get total ordering across multiple Kafka topics?
A: Not without external coordination. Each topic is independent. If two topics need joint ordering (e.g., to build a global timeline), you typically either republish them to a single keyed topic or use Kafka Streams' time-based joins, which give you windowed ordering rather than strict total order.