Producing a Message in Kafka
What really happens between the moment your program decides to send an event and the moment Kafka considers it safely written. A close look at the journey of a single message.
Imagine dropping a registered letter into a post office counter instead of an ordinary street mailbox. You do not just push it through a slot and walk away; the clerk weighs it, decides which sorting route it should follow, stamps it, and hands you a receipt confirming it is now safely in the system. Only then do you leave, confident the letter is tracked and will not simply vanish. Sending, or producing, a message in Kafka works remarkably similarly: there is far more happening behind that one simple action than most beginners expect.
1The Big Picture: What Does “Producing” Mean?
Producing simply means a program creating a piece of data and handing it to Kafka to be stored and eventually delivered.
In Kafka’s world, any program that creates and sends data is called a producer. A producer might be a website’s checkout service announcing “an order was placed,” a mobile app reporting “the user tapped this button,” or a factory sensor reporting “the temperature just changed.” Whatever the source, the act of producing is the same: package up a small piece of information, called a message or an event, and send it to a specific topic, Kafka’s named, ordered stream for that kind of data.
It is tempting to imagine this as a single, instant action, throw the message and forget it, but Kafka producers are actually careful, deliberate pieces of software. They decide exactly where a message should go, how to describe it, whether to wait for confirmation, and what to do if something goes wrong along the way.
Sending an SMS through a mobile network is not really “instant” either, even though it feels that way. The message is handed to a tower, routed through the network, confirmed as delivered, and only then does your phone show the little checkmark. Producing a message to Kafka involves a similar, careful hand-off, just measured in milliseconds instead of seconds.
2The Anatomy of a Kafka Message
Before a message can be sent, it needs to be assembled from a few distinct pieces, each with its own job.
Topic
The named stream the message is destined for, such as “orders” or “user-signups.” Every message belongs to exactly one topic.
Key
An optional label, such as a customer ID, used to decide which partition the message lands in and to keep related messages in order.
Value
The actual payload, the real content being communicated, such as the details of an order.
Headers
Small optional metadata tags attached to the message, such as which system produced it or a tracing identifier.
Timestamp
The moment the message was created or sent, recorded automatically or set explicitly by the producer.
Partition (Optional)
A specific partition number can be chosen directly, bypassing the usual key-based decision entirely.
Think of a courier package. The topic is the destination city, the key is the customer’s account number used to route it to the right local depot, the value is what is actually inside the box, and headers are the extra stickers, “fragile,” “priority,” attached to the outside.
3How a Message Chooses Its Partition
A topic is usually split into several partitions, and every message needs a clear, predictable way of landing in exactly one of them.
When a message includes a key, Kafka runs that key through a consistent formula, called a hashing function, which always produces the same partition number for the same key. This means every message about, say, “customer 88” will always land in the same partition, keeping that customer’s history in perfect order.
When a message has no key at all, Kafka instead spreads messages across all available partitions in a rotating, balanced pattern, so that no single partition becomes overloaded while others sit idle. This is a reasonable default when strict per-entity ordering does not matter.
flowchart LR
M1["Message: key=customer-88"] --> H{Hash the Key}
H --> P1[Partition 1]
M2["Message: key=customer-42"] --> H2{Hash the Key}
H2 --> P2[Partition 2]
M3["Message: no key"] --> R{Round-Robin}
R --> P0[Partition 0]
R --> P1
R --> P2
Choosing a good key matters more than it might first appear. Related events that must stay in order, all actions for one customer, for example, should always share the same key so they are guaranteed to land in the same partition.
4Serialization: Turning Data Into Bytes
Before a message can travel across a network, it must be converted from a program’s internal data structure into a flat, transportable format.
This conversion process is called serialization. A producer takes a structured piece of data, perhaps an object representing an order with a customer name, items, and a total price, and flattens it into a simple sequence of bytes that any system can transmit and store, regardless of what programming language wrote it. On the receiving end, a consumer reverses this process, called deserialization, turning the bytes back into a usable structure.
Common Serialization Formats
Plain text formats like JSON are popular for their simplicity and readability. More compact, structured formats like Avro or Protobuf are common in larger systems because they are smaller, faster, and can enforce a strict, agreed-upon shape for the data.
Serialization is like folding a full-size paper airplane design into a flat sheet before mailing it overseas. The recipient unfolds it back into the exact same shape on arrival. Both sides must agree on the folding pattern, or the shape gets lost in translation.
Changing a message’s structure without warning the teams consuming it. If a field is renamed or removed without coordination, consumers expecting the old shape can fail unexpectedly while trying to deserialize the new messages.
5The Journey of a Message, Step by Step
From the instant a program decides to send something, to the moment it is durably stored, a message passes through several distinct stages.
The application builds the message
The producer assembles the topic, key, value, and any headers into a single message ready to send.
The message is serialized
The key and value are converted into raw bytes using the agreed serialization format.
A partition is chosen
Based on the key, or a rotating pattern if there is no key, Kafka determines exactly which partition will receive it.
The message enters a local batch
Rather than sending one message at a time, the producer briefly groups it with other messages headed to the same partition.
The batch is sent to the leader broker
The producer sends the batch across the network to the broker currently acting as leader for that partition.
The broker writes and confirms
The leader appends the message to its log, waits for whatever acknowledgement level was configured, and sends confirmation back.
sequenceDiagram
participant App as Application
participant Prod as Producer
participant B as Broker (Leader)
App->>Prod: Build message
Prod->>Prod: Serialize + choose partition
Prod->>Prod: Add to batch
Prod->>B: Send batch
B->>B: Append to partition log
B-->>Prod: Acknowledge
Prod-->>App: Confirm send success
6Batching: Why Kafka Groups Messages Together
Sending one tiny network request per message would be wasteful. Kafka producers are smart enough to bundle messages together first.
Rather than firing off a separate network call for every single message, a producer briefly holds newly created messages in a small local batch, grouped by which partition they are headed to. Once the batch reaches a certain size, or a short amount of time passes, whichever happens first, the entire batch is sent together in one network request.
| Setting | What It Controls | Effect of a Larger Value |
|---|---|---|
| Batch Size | How much data can accumulate before a batch is sent | Fewer, larger network requests; slightly higher delay per message |
| Linger Time | How long the producer waits, hoping more messages arrive to batch together | Better batching efficiency; slightly higher delay before the first send |
Batching is like a delivery van waiting a few extra minutes to see if more packages for the same neighborhood arrive before setting off, rather than making a separate trip for every single parcel. A little patience saves a great deal of fuel and time overall.
Batching is one of the biggest reasons Kafka can handle such enormous throughput. Fewer, larger network trips are dramatically more efficient than a flood of tiny individual ones.
7Acknowledgements: How Sure Should the Producer Be?
Once a message is sent, Kafka lets the producer decide exactly how much proof it wants before considering the send truly successful.
This setting is often called acks, short for acknowledgements, and it is one of the most important decisions a producer makes. It controls a direct trade-off between speed and safety: waiting for less confirmation is faster but riskier, while waiting for more confirmation is safer but slightly slower.
| Acks Setting | What It Waits For | Risk If Something Fails |
|---|---|---|
| acks = 0 | Nothing at all; fires and moves on immediately | The message could be lost entirely without the producer ever knowing |
| acks = 1 | Only the leader broker confirms it has the message | If the leader fails right after, before followers copy it, the message can still be lost |
| acks = all | Every in-sync replica confirms it has the message | Very low risk of loss, at the cost of a little extra waiting time |
Using acks = 0 for genuinely important data, such as payment events, purely to shave off a little latency. The speed gained rarely justifies the risk of silently losing critical business data.
8What Happens When Sending Fails
Networks glitch, brokers restart, and messages do not always reach their destination on the first try. Producers are built to handle this gracefully.
If a producer does not receive the expected acknowledgement in time, it typically assumes the send may have failed and automatically retries, sending the same batch again. This built-in resilience is one of Kafka’s strengths, but it introduces a subtle new problem: what if the original message actually did succeed, and only the acknowledgement was lost on its way back? The retry could then create a duplicate.
Idempotent Producers
To solve this, Kafka supports a mode where each producer is given a unique identity, and every message it sends carries a sequence number. The broker can then recognize and silently discard an accidental duplicate caused by a retry, ensuring each message is written exactly once despite the retry happening.
Send attempt is made
The producer sends the batch and starts waiting for acknowledgement.
No acknowledgement arrives in time
A network hiccup or broker slowdown means the confirmation never comes back before the timeout.
The producer automatically retries
It sends the same batch again, following its configured retry policy.
The broker recognizes a duplicate, if idempotence is enabled
Using the sequence number, the broker safely ignores the repeated attempt if the original already succeeded.
Even without idempotence enabled, a consumer built to treat repeated messages safely, an idempotent consumer, provides a second layer of protection against the occasional duplicate.
9Synchronous vs Asynchronous Sending
A producer can be told to wait for confirmation before continuing, or to keep working and check on the result later.
In synchronous sending, the application pauses and waits until it receives confirmation that the message was safely written before moving on to its next task. This is simple to reason about but can slow the application down, since every send briefly blocks other work.
In asynchronous sending, the application fires the message off and immediately continues with other work, without waiting. A callback, a small piece of code that runs later, is triggered once the result, success or failure, eventually becomes known. This approach is far more efficient for high-throughput systems.
Synchronous Sending
- Simple, predictable, easy-to-follow logic.
- Guarantees the application knows the outcome before proceeding.
- Slower overall, since each send briefly pauses the application.
Asynchronous Sending
- Much higher throughput, since sends do not block other work.
- Requires careful callback handling to catch failures properly.
- Slightly more complex code to write and reason about.
10Ordering Guarantees While Producing
Producers play a direct role in whether messages end up in the correct order once they are stored.
Because all messages sharing the same key always land in the same partition, and a single partition always writes messages in the exact order it receives them, choosing a consistent key is the single most important decision a producer makes for ordering. Messages sent without a key, spread across multiple partitions, carry no such guarantee relative to each other.
Retries introduce a subtlety here too: if retries are not handled carefully, an older message that needed to be resent could theoretically be written after a newer message that succeeded on its first attempt. Kafka’s idempotent producer mode specifically protects against this, preserving the original sending order even through retries.
Picture a queue of people at a single ticket counter, always served in the order they arrived. But if someone briefly steps out of the line and rejoins later, without a clear rule about where they re-enter, they might accidentally cut ahead of people who were originally behind them. Idempotent producers are the rule that puts them firmly back in their correct original spot.
11Real-World and Industry Examples
Producing messages carefully and correctly is the foundation every downstream Kafka use case is built on.
E-commerce Checkout Flows
An order service produces an “order placed” event, keyed by customer ID, so every action for a single customer stays in strict, correct order.
Ride-Hailing Location Updates
A driver’s mobile app produces a location event every few seconds, keyed by driver ID, ensuring the route history for one driver is always consistent.
Banking Transaction Systems
Payment services almost always use acks = all together with idempotent producers, since losing or duplicating a financial transaction is simply unacceptable.
IoT Sensor Networks
Thousands of sensors produce readings continuously, often without keys, spreading evenly across many partitions for maximum parallel throughput.
Clickstream and Analytics Pipelines
Web and mobile apps produce a steady stream of user interaction events, usually favoring speed with a lighter acknowledgement setting since occasional loss is tolerable.
12Advantages, Disadvantages and Trade-offs
Producing messages carefully takes some deliberate configuration, but each choice trades off against another.
Advantages of Careful Production
- Strong ordering guarantees when related messages share a sensible key.
- High throughput thanks to efficient batching of messages before sending.
- Resilience against network hiccups through automatic retries.
- Protection against accidental duplicates when idempotence is enabled.
Disadvantages / Trade-offs
- Stronger acknowledgement settings add a little extra latency to every send.
- Batching introduces a small, deliberate delay before messages are actually sent.
- Poor key choices can create uneven load across partitions.
- Handling retries and duplicates correctly adds real design complexity.
13Security While Producing
A producer is often the very first point where sensitive data enters a Kafka system, making it a natural place to enforce security.
Authentication
The producer should prove its identity to the broker before it is allowed to send anything at all.
Authorization
Even an authenticated producer should only be permitted to write to the specific topics it genuinely needs.
Encryption in Transit
Data traveling from the producer to the broker should be encrypted, so it cannot be read if intercepted along the way.
Careful Payload Design
Avoid placing highly sensitive raw data directly into a message’s value when a safe reference or masked version would do.
Since Kafka can retain messages for a long time, anything written by a producer today may still be readable weeks or months later. Think carefully about what actually belongs in a message before it is sent.
14Monitoring a Producer’s Health
A producer that looks fine from the outside can still be quietly struggling. A few key numbers reveal the truth.
Send Error Rate
How often sends are failing outright, a direct signal of trouble reaching the broker.
Retry Rate
How often messages need to be resent, often an early warning of network or broker instability.
Request Latency
How long it takes for a send to be acknowledged, which directly affects how quickly the application can proceed.
Batch Size and Fill Rate
Whether batches are filling up efficiently or being sent mostly empty, revealing whether batching settings are well tuned.
A sudden rise in retry rate, even without outright failures, is often the earliest sign of a struggling broker, well before anything looks obviously broken elsewhere.
15Design Patterns and Anti-patterns
A few consistent habits separate producers that behave predictably from ones that cause quiet, hard-to-trace problems later.
Helpful patterns
- Consistent keying — always use the same key for related events, so their order is preserved.
- Idempotent production — enable it whenever accidental duplicates would cause real harm.
- Asynchronous sending with proper callbacks — for high-throughput systems that cannot afford to block.
- Schema agreement — settle on a message format and version it deliberately, rather than changing it silently.
Problem
Using a single, tiny message per network call for a high-volume producer, disabling or ignoring batching entirely.
Why It’s Harmful
An enormous number of tiny network requests is far less efficient, wasting both producer and broker resources that could be spent handling far more data.
Correct Approach
Allow the producer to batch messages naturally, tuning batch size and linger time to match the traffic pattern.
Problem
Picking a key with very few distinct values, such as always using a fixed region name for millions of events.
Why It’s Harmful
All those messages pile into just a handful of partitions, leaving other partitions idle and creating an uneven, inefficient load across the cluster.
Correct Approach
Choose a key with enough natural variety, such as an individual customer or device ID, to spread load evenly while still preserving the order that actually matters.
Problem
Ignoring the result of an asynchronous send entirely, with no callback checking whether it actually succeeded.
Why It’s Harmful
A silently failed send can mean an important event simply never happened as far as the rest of the system is concerned, with no one aware anything went wrong.
Correct Approach
Always attach a callback or equivalent check to every asynchronous send, logging or handling failures deliberately rather than assuming success.
16Best Practices and Common Mistakes
A short checklist for producing messages with confidence.
Best Practices
- Choose keys deliberately, based on what genuinely needs to stay in order.
- Match the acknowledgement setting to how critical the data actually is.
- Enable idempotent production for anything sensitive to duplicates.
- Handle send failures explicitly rather than assuming every send succeeds.
- Agree on and version the message format ahead of time.
Common Mistakes
- Using acks = 0 for data that genuinely cannot afford to be lost.
- Choosing keys with too little variety, overloading a small number of partitions.
- Ignoring retry and error metrics until customers notice something is wrong.
- Changing a message’s structure without coordinating with the teams consuming it.
17Frequently Asked Questions
No, a key is optional. Without one, Kafka spreads messages evenly across all partitions using a rotating pattern instead of routing by key.
Grouping messages together into a batch dramatically reduces the number of network requests needed, which is one of the main reasons Kafka can handle such high volumes of data efficiently.
Acks = all offers the strongest protection, since it waits for every in-sync replica to confirm the message before considering the send successful, at the cost of slightly higher latency.
Yes, this can happen if an acknowledgement is lost and the producer retries a message that actually already succeeded. Enabling idempotent production specifically prevents this from creating a true duplicate.
Not always. It offers much higher throughput, which suits high-volume systems, but synchronous sending can be simpler to reason about for lower-volume or simpler applications.
The producer detects the failure and automatically redirects the send to the newly elected leader, usually with only a brief delay, and without requiring any manual intervention.
It is strongly recommended, and usually enforced through an agreed schema, since consumers rely on a predictable, consistent shape to correctly deserialize and process every message they receive.
18Summary and Key Takeaways
We began at a post office counter and ended inside the careful, multi-step journey a message takes through a Kafka producer. Producing a message is never truly as simple as “send and forget”; it involves choosing a partition through a key, serializing data into a transportable form, batching efficiently for performance, deciding how much confirmation to demand, and gracefully handling the retries and duplicates that inevitably happen in any real network. Understanding this full journey is what separates a system that occasionally loses or duplicates data from one that behaves reliably, even under real-world failure conditions.
Key Takeaways
- A message has several parts — topic, key, value, headers, and timestamp each play a distinct role in how it is handled.
- Keys decide the partition — a consistent key keeps related messages in strict, correct order.
- Serialization makes data transportable — structured data is flattened into bytes before it can travel across the network.
- Batching drives efficiency — grouping messages together dramatically improves throughput.
- Acks is a deliberate trade-off — more confirmation means more safety, at the cost of a little extra latency.
- Retries can create duplicates — idempotent production protects against this without sacrificing resilience.
- The job isn’t done at send time — a well-built producer always checks and handles the eventual outcome of every send.