Exactly-Once and Delivery Guarantees

"Exactly-once" is streaming's most abused phrase — simultaneously a real, shippable feature and a physical impossibility, depending entirely on which claim is being made. This page separates the claims: what the three delivery levels actually promise, what Kafka's transactions do and don't cover, and why the durable engineering answer is idempotency at the edges.

The three levels, stated precisely

So the engineering question is never "is delivery exactly-once?" but "is the effect idempotent or transactional?"

Kafka's machinery: idempotent producers and transactions

Two mechanisms, often conflated:

  1. Idempotent producer (default since Kafka 3.0): producer IDs + per-partition sequence numbers let brokers discard retry-duplicates. Kills the classic duplicate source — producer retries — at zero design cost. Scope: one producer session, within the cluster.
  2. Transactions: a producer atomically writes to multiple partitions and commits consumer offsets in the same transaction; downstream readers in read_committed mode see all-or-nothing. This enables the consume-transform-produce loop — the Kafka Streams / Flink-to-Kafka pattern — to be exactly-once end-to-end within the Kafka world: reprocessing after a crash cannot double-count because the offset commit and the output write share one transaction.

The boundary is the point: the guarantee holds from Kafka to Kafka. The moment an effect leaves the transactional domain — an HTTP call, an email, a database without coordinated commit — the guarantee stops at the border.

Crossing the border: transactional sinks and the outbox

Effectively-once: the design stance

Mature systems assume at-least-once transport + idempotent effects everywhere — "effectively once." Concretely: natural or deterministic idempotency keys on every externally visible effect; upserts over inserts; versioned or conditional writes; dedup windows where keys are impractical (JetStream's approach); and treating any claimed exactly-once as a scoped guarantee whose boundary you can name. The test worth applying to every pipeline: replay yesterday against every sink — what breaks? If the answer is "nothing," you have the only exactly-once that survives contact with production. This stance also composes with event-time logic: replayable, idempotent, event-timed pipelines are the ones you can rerun after bugs — the property that makes streaming systems fixable.

See Also