Kafka Producer
Message Delay
Data Streaming
Apache Kafka
Programming Tips

Is there a way to set a delay for a message sent by a kafka producer?

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

Introduction

Kafka producers are built to publish records immediately, not to hold them until a scheduled delivery time. If you need delayed delivery, you have to implement that behavior in your application or architecture rather than expecting a built-in per-message delay setting on the producer itself.

What Kafka Producers Actually Do

A producer batches, compresses, retries, and sends records to brokers as soon as the client decides they are ready. Settings such as linger.ms can delay batching slightly, but that is a throughput optimization measured in small intervals, not a scheduling feature for business logic.

So the short answer is: no, there is no standard Kafka producer property that says "deliver this record 10 minutes later."

Option 1: Delay Before Sending

If the delay is simple and local to the producing application, schedule the send on your side.

java
1import java.util.concurrent.Executors;
2import java.util.concurrent.ScheduledExecutorService;
3import java.util.concurrent.TimeUnit;
4import org.apache.kafka.clients.producer.KafkaProducer;
5import org.apache.kafka.clients.producer.ProducerRecord;
6
7ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
8KafkaProducer<String, String> producer = buildProducer();
9
10scheduler.schedule(() -> {
11    producer.send(new ProducerRecord<>("orders", "123", "ship-later"));
12}, 30, TimeUnit.SECONDS);

This is easy to understand and works when the producer process is trusted to stay alive for the whole delay period.

Option 2: Store A Due Time In The Message

For more durable workflows, put the intended execution time in the message and let consumers enforce it.

java
1import org.apache.kafka.clients.producer.ProducerRecord;
2
3long dueAt = System.currentTimeMillis() + 30_000;
4ProducerRecord<String, String> record = new ProducerRecord<>("orders", "123", "ship-later");
5record.headers().add("dueAt", Long.toString(dueAt).getBytes());
6producer.send(record);

A consumer can read the header, compare it with the current time, and decide whether to process now, requeue, or park the work elsewhere.

java
1long dueAt = Long.parseLong(new String(record.headers().lastHeader("dueAt").value()));
2if (System.currentTimeMillis() < dueAt) {
3    return;
4}
5process(record.value());

This pattern survives producer restarts better because the due time is stored with the message itself.

Option 3: Use A Delay Topic Or Scheduler Service

A common architecture is to publish first to a dedicated delay topic or database-backed scheduler, then move the record to the real topic when it becomes due. That adds infrastructure, but it is often cleaner when delays are measured in minutes or hours and reliability matters.

This design also keeps the main Kafka topic semantically clear: once a record arrives there, consumers can treat it as ready for processing.

Ordering And Delivery Tradeoffs

Delayed delivery is not just a timing problem. It can also affect ordering. If one record is delayed and a later record is sent immediately, consumers may observe them in a different business order than the application originally created them.

That is why delay logic should be designed around the business rule, not just the producer API. Sometimes the right answer is actually a workflow engine, a task scheduler, or a retry service rather than raw Kafka alone.

Common Pitfalls

A common mistake is using linger.ms as if it were a real scheduling feature. It only holds small batches briefly to improve efficiency and should not be used for user-visible delays.

Another mistake is sleeping inside hot producer threads for long periods. That ties up resources and can make throughput unpredictable.

It is also easy to forget persistence. If the application crashes before a scheduled send runs, the delayed message may never be produced unless the schedule itself is stored durably.

Summary

  • Kafka producers do not have a built-in per-message delayed delivery feature.
  • 'linger.ms is for batching efficiency, not business scheduling.'
  • For short delays, schedule the send in application code.
  • For durable workflows, store a due time in the message or use a delay topic or scheduler service.
  • Think about ordering and crash recovery before choosing a delay strategy.

Related reading
Course
Beginner
27 lessons
10 hours
System Design Fundamentals

Build a strong foundation in designing scalable, reliable distributed systems.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design