skip to content

Event-Driven Design with Kafka

Designing the events themselves: events versus commands, fat versus thin payloads, choreography versus orchestration, and versioning. A system-design favourite, because these choices outlive the code that makes them.

part ofApache Kafkaoverview, primer and where to startread it →
on this pageshow

questions

6

What is the difference between an event and a command in an event-driven system, and how does that distinction shape how you name and publish messages to Kafka topics?

level: juniorimportance: must knowfreq 78%

answer

  1. Event = past tense fact; command = imperative intent
  2. Event: publisher doesn't know consumers
  3. Command: sender knows receiver (coupling)
  4. OrderPlaced vs PlaceOrder
  5. Kafka topic = natural event bus; commands need keyed/dedicated topic

basics

~20 s

An event states something that already happened (past tense, e.g. OrderPlaced) and has no specific intended recipient. A command tells one service to do something (imperative, e.g. PlaceOrder) and expects an action. Events go to topics for any consumer; commands target one handler.

solid answer

~50 s

An event is an immutable fact about something that already occurred — named in the past tense like OrderPlaced or PaymentCaptured. The publisher does not know or care who consumes it; any number of consumers can subscribe to the topic. A command is an intent/instruction directed at a specific service to perform an action — named imperatively like ShipOrder — and the sender expects it to be handled (often exactly once). In Kafka, both can be serialized to topics, but events are the natural fit: producers broadcast facts to a topic, consumers in independent consumer groups each read them. Commands over Kafka usually use a dedicated topic keyed so one logical handler processes them, and they imply a sender-knows-receiver coupling. Mixing them up leads to producers encoding behavior expectations into 'events', which couples services. The naming convention (past-tense vs imperative) is the simplest discipline that keeps the distinction visible.

go deeper

for a junior

Recall the past-tense vs imperative naming and that events have unknown consumers while commands target one.

for a middle

Explain the coupling-direction inversion and how each maps onto Kafka topics/keys.

for a senior

Reason about request/reply, once-only command handling, and when a direct RPC beats a command topic.

for a principal

Set org-wide conventions for naming, topic taxonomy (events vs commands), and review gates that keep the semantics honest at scale.

## First principles A **message** is any piece of data one service sends to another. Event-driven design distinguishes two kinds of message by *intent*: - **Event** — a statement that **something already happened**. It is a *fact*, it is immutable, and it is named in the **past tense**: `OrderPlaced`, `PaymentCaptured`, `InventoryReserved`. The publisher emits it and **does not know who, if anyone, will consume it**. Zero, one, or many consumers may react. The publisher has *no expectation* about what happens next. - **Command** — an **instruction to do something**, named in the **imperative**: `PlaceOrder`, `ShipOrder`, `ReserveInventory`. It is directed at a **specific** recipient, the sender **expects** it to be acted on, and it can be **rejected** (the action might not be valid). It typically should be handled **once**. The mnemonic: an event says *'this is true'*; a command says *'please make this true'*. ## Why it matters for coupling The direction of knowledge differs: - With a **command**, the **sender knows the receiver** ('I want *the shipping service* to ship this'). That is a form of coupling — the sender depends on the existence of a handler. - With an **event**, the **publisher knows nothing about subscribers**. Consumers depend on the event, not the other way round. This *inverts the dependency* and is what makes event-driven systems loosely coupled and extensible: you can add a new consumer (analytics, fraud, email) without touching the producer. ## How this maps onto Kafka Kafka is a **partitioned, durable log**. A producer appends records to a **topic**; **consumer groups** each maintain their own offset and read independently. This is a natural **event** transport: one topic of `OrderPlaced` events can be consumed by the billing group, the analytics group, and the email group at once, each at its own pace. Commands can also be sent over Kafka, but with a different shape: - Use a **dedicated command topic** (e.g. `shipping.commands`). - **Key** the record so a single logical consumer/partition handles each command, preserving per-entity ordering. - Accept that the sender now depends on that handler existing. ## Edge cases & pitfalls - **'Eventy commands'**: emitting `OrderPlaced` but secretly expecting *exactly one* service to ship the order, and breaking if a second consumer appears — that is a command wearing an event's name. Keep semantics honest. - **Request/reply over Kafka**: a command often wants a result. You implement reply with a correlation id and a reply topic, but this reintroduces synchronous-style coupling — sometimes a direct REST/gRPC call is simpler. - **Naming discipline** is the cheapest enforcement: reviewers can reject a past-tense name on a command topic or an imperative name on a domain-event topic. - Both events and commands should carry a **schema** (Avro/Protobuf/JSON Schema in a registry) so consumers/handlers can evolve safely.

  • Can you send a command over Kafka, and what changes versus an event?
    Yes — use a dedicated command topic, key records so one logical handler processes each, and accept that the sender now couples to that handler. Unlike events, you usually want once-only handling and sometimes a reply via correlation id + reply topic.
  • How does the event-vs-command distinction affect coupling direction?
    With commands the sender depends on the receiver. With events the dependency inverts — consumers depend on the event, the publisher knows nothing about subscribers — which is what enables adding consumers without changing producers.

saying these in an interview costs you the question

  • Saying events and commands are the same thing with different names
  • Claiming the event publisher chooses which consumer handles the event
  • Naming a command in past tense or an event in imperative form
  • Believing Kafka can only carry events, never commands

context

open as a page

Compare fat (event-carried state transfer) events versus thin (notification) events. What are the trade-offs, and when would you choose each for a Kafka topic?

level: middleimportance: must knowfreq 70%

basics

~20 s

A thin event carries only an id/reference, so consumers must call back to fetch details. A fat event carries the full state, so consumers need no callback but the payload is larger and may go stale. Fat reduces coupling/load; thin keeps payloads small and authoritative.

open as a page

Explain choreography versus orchestration for coordinating a multi-service business process (e.g. an order saga) over Kafka. What are the trade-offs and failure-handling implications of each?

level: seniorimportance: must knowfreq 68%

basics

~20 s

In choreography each service reacts to events and emits its own, with no central coordinator — logic is distributed. In orchestration a central orchestrator tells each service what to do and tracks progress. Choreography is decoupled but hard to trace; orchestration is centralized, explicit, and easier to monitor.

open as a page

How do you evolve the schema of a domain event published to a Kafka topic without breaking existing consumers? Discuss compatibility modes and what changes are safe.

level: seniorimportance: must knowfreq 72%

basics

~20 s

Use a schema registry (Avro/Protobuf/JSON Schema) and a compatibility mode. The safest common choice is BACKWARD: new consumers can read old data. Safe changes are adding optional fields with defaults and removing optional fields; renaming or removing required fields breaks compatibility.

open as a page

How should you design Kafka topics for domain events — granularity (one event type per topic vs many), keying, and retention/compaction — and what is a domain event versus an integration event?

level: middleimportance: should knowfreq 55%

basics

~20 s

A domain event captures something meaningful in the business domain (OrderPlaced). Design topics around an aggregate/entity, key events by the aggregate id for ordering, choose one-type-per-topic for clarity or grouped types for related events, and use compaction for state-style events and time retention for pure notifications.

open as a page

Your services share data via Kafka domain events instead of synchronous calls, so they are eventually consistent. What does eventual consistency mean here, what problems does it introduce, and how do you handle them?

level: seniorimportance: should knowfreq 60%

basics

~20 s

Eventual consistency means each service updates its own copy of data after processing an event, so for a short window different services hold different values until events propagate. You handle it with idempotent consumers, ordering by key, versioning to drop stale updates, and designing UX to tolerate the lag.

open as a page