The 30 second answer
On restart or rebalance the partition resumes from the last committed offset, so the message is processed again. That is at-least-once delivery. Effects must be idempotent: a dedupe table keyed by message or business id, upserts, or idempotent downstream APIs. Kafka transactions can give exactly-once inside Kafka, but external side effects still need idempotency. Committing before processing flips you to at-most-once and can lose work.
On restart/rebalance the partition resumes from the last committed offset → the message is processed again (at-least-once). Effects must be idempotent: dedupe table keyed by message/business id, upserts, idempotent downstream APIs. For Kafka→Kafka pipelines, transactions (read_committed + offsets committed in the producer transaction) give exactly-once within Kafka; external side effects still need idempotency. (Committing before processing flips it to at-most-once → loss.)
Sources: