This episode covers log compaction: the compact cleanup policy that stores the latest value per key, tombstones for deletion, compaction parameters such as min.compaction.lag.ms and min.cleanable.dirty.ratio, and use cases like changelog topics, materialized views, and state stores.

In episode 4 you already got a brief look at the compact cleanup policy. Now we dissect it fully. Log compaction is Kafka's mechanism for cleaning up logs differently from retention delete: instead of discarding data based on age, compaction discards all old versions of a key and only retains the latest value.
Why does this matter? Imagine the user-profiles topic: every profile update writes a new record with the user_id key. Over time, most of the data in the log is old versions that are no longer relevant. With compaction, Kafka condenses the log into one latest value per user — without losing current information.
Episode 10 covers the concept of compaction with tombstones, the configuration parameters that control its behavior, real-world use cases like changelog topics and materialized views, and how to monitor compaction health.
With cleanup.policy=compact, brokers don't delete records by time; instead they maintain the log so that for every key only the latest value is stored. Older records with the same key are discarded by a background process called the cleaner.
Compaction preserves one snapshot per key while still keeping records with unique keys as long as retention applies. As a result, the amount of data in a compacted topic keeps approaching the number of keys, not the number of writes.
How do you fully delete a key? The answer is a tombstone: a record with a given key and a null value. The cleaner treats a tombstone as a "delete this key" marker and removes that key from the log along with all its previous versions.
Before : (k1,v1) (k1,v2) (k2,v1) (k1,v3) (k2,v2) (k2,null)
After : (k1,v3) (k2,null)The tombstone itself doesn't disappear immediately; it's held for delete.retention.ms before being deleted too. This gives consumers time to catch the deletion event.
Note an important nuance: compaction is not a real-time guarantee. Records in an active, still-open segment cannot be compacted. Compaction only works on segments that are already closed and sufficiently "dirty" (containing many stale versions), so the newest data stays intact while the active segment is still receiving writes.
Compaction configuration is set per topic via kafka-configs.sh:
bin/kafka-configs.sh --bootstrap-server localhost:9092 \
--alter --entity-type topics --entity-name user-profiles \
--add-config cleanup.policy=compact,min.compaction.lag.ms=60000,min.cleanable.dirty.ratio=0.5Key parameters you need to understand:
cleanup.policy=compact
min.compaction.lag.ms=60000
max.compaction.lag.ms=300000
delete.retention.ms=86400000
min.cleanable.dirty.ratio=0.5A rule of thumb: a low min.cleanable.dirty.ratio makes compaction more frequent (more CPU) but keeps the log more compact; a high value saves CPU but lets the log grow longer. The combination of min.compaction.lag.ms and delete.retention.ms must be planned so slow consumers don't lose data.
Kafka Streams stores state in state stores and replicates it through changelog topics with cleanup.policy=compact. Since only the latest value per key is needed for state recovery, compaction keeps the changelog small. Materialized views built from compacted topics automatically represent the current state.
RocksDB and other state stores use compacted changelogs for recovery: when an instance crashes, it reads the changelog from the last checkpoint position. Without compaction, recovery would have to read the entire history; with compaction, only the latest snapshot per key.
Change Data Capture patterns (episode 27) often write database changes to compacted topics. A single compacted accounts topic represents the latest database table: each key is a primary key, and the latest value is the current state of that row. A data warehouse can be rebuilt by reading the full snapshot at any time.
Brokers expose metrics for the cleaner process via JMX:
Compaction is said to be lagging when there are old segments that never get cleaned, usually because max.compaction.lag.ms is too large or the cleaner lacks threads. Monitor two things: the number of segments exceeding max.compaction.lag.ms, and a dirty ratio that keeps rising. Both indicate the cleaner can't keep up with the write rate.
bin/kafka-run-class.sh kafka.tools.JmxTool --object-name kafka.log:type=LogCleaner,name=clean-time-percent --report-format=txtkafka.tools.JmxTool is a built-in tool for reading JMX metrics from the terminal. In production practice, these metrics are more often collected into Prometheus (details in episode 22).
Info
Compaction is not time-based deletion. You still need retention delete to bound the overall age of data, and compaction to summarize values per key. The combination cleanup.policy=compact,delete uses both at once.
In this episode 10 you've understood that log compaction condenses a log into the latest value per key, how tombstones delete keys, configuration parameters like min.compaction.lag.ms, max.compaction.lag.ms, delete.retention.ms, and min.cleanable.dirty.ratio, and the changelog topic, materialized view, state store, and CDC use cases.
The key takeaways:
compact,delete combines per-key summarization with data age limits.In the next episode 11 we'll discuss tiered storage (KIP-405) — Kafka's ability to offload old segments to object storage like S3, GCS, and Azure Blob. You'll learn remote storage configuration, the difference between local and remote retention, and the storage cost versus read latency trade-offs.