Dead letter queue (DLQ) for Kafka with spring-kafka
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
Kafka does not have a built-in dead letter queue object, but it is common to implement the same pattern with a dedicated Kafka topic. In Spring Kafka, the standard approach is to use an error handler plus a DeadLetterPublishingRecoverer so failed records are retried and then published to a dead-letter topic instead of blocking the consumer forever.
What a DLQ Solves
When a consumer cannot process a record because of bad data, a deserialization problem, or a downstream business failure, you usually want one of two outcomes:
- retry the message a few times
- if it still fails, move it aside for inspection
A DLQ topic provides that second destination. It keeps the main consumer flowing while preserving the failed record for analysis or reprocessing.
The Core Spring Kafka Pieces
In modern Spring Kafka, the usual components are:
- '
DefaultErrorHandler' - '
DeadLetterPublishingRecoverer' - '
KafkaTemplate'
DefaultErrorHandler handles retries. DeadLetterPublishingRecoverer decides how to publish the failed record once retries are exhausted.
A Typical Configuration
This means:
- try processing
- retry twice with a one-second delay
- if it still fails, publish to the dead-letter topic
By default, the dead-letter topic name is often based on the original topic plus a suffix such as .DLT.
Listener Example
If a record keeps failing, the error handler pushes it to the dead-letter topic instead of letting it poison the consumer forever.
Customizing the Dead-Letter Topic
You can route failures to a custom topic instead of the default naming convention:
That is useful when you want a stable operational topic name or different routing rules based on exception type.
Why a DLQ Is Better Than Infinite Retry
Infinite retries can stall a consumer partition on one bad record. In some systems that is exactly what you want, but in many event-processing pipelines it is better to capture the failure and move on.
A DLQ also helps operations teams answer questions like:
- which records are failing repeatedly
- which exception types are most common
- do we need replay or data repair tools
Without a DLQ, those failures are harder to inspect systematically.
Handling DLT Records
A DLQ is not the end of the design. You should decide what happens next:
- manual inspection
- an admin replay tool
- an automated repair consumer
- alerting and dashboards
The dead-letter topic is valuable only if the team knows how to observe and act on it.
Common Pitfalls
One common mistake is following older examples that use deprecated handler classes and assuming they are still the current recommendation. In newer Spring Kafka code, DefaultErrorHandler is the standard place to start.
Another issue is sending everything to the DLQ immediately with no retry policy, even for transient failures such as brief network issues. Retries and DLQs should work together.
A third pitfall is creating a DLQ topic but never monitoring it. That simply moves failures to a quieter place instead of solving them operationally.
Summary
- In Spring Kafka, a DLQ is usually implemented as a separate Kafka topic.
- Use
DefaultErrorHandlerwithDeadLetterPublishingRecovererfor the standard pattern. - Retries happen first; failed records can then be published to a dead-letter topic.
- Customize DLT routing when you need stable names or exception-based behavior.
- A DLQ is useful only if the team also monitors and handles the failed records.

