Designing Domain Events
You'll learn to
- -Name and shape domain events so they describe what happened, not what should happen next
- -Decide how much data to include in an event payload - a thin reference versus a full snapshot
An event-driven API communicates through a different mechanism than request-response: services publish events describing things that have already happened, and other services subscribe to react to them, fully decoupled from whoever produced the event. Designing the events themselves well is just as much an API design discipline as designing REST endpoints or a GraphQL schema.
Naming: Past Tense, Not Commands
{
"event_type": "order.shipped",
"event_id": "evt_7f3a2b1c",
"occurred_at": "2026-08-07T14:30:00Z",
"data": {
"order_id": 501,
"tracking_number": "1Z999AA10123456784",
"shipped_at": "2026-08-07T14:30:00Z"
}
}Event names should be past-tense facts (`order.shipped`, `payment.completed`) rather than imperative commands (`ship_order`, `complete_payment`) - a command implies an instruction the receiver must obey, which couples the publisher to what subscribers should do. An event, by contrast, is just a statement of fact: "this happened," leaving each subscriber free to decide independently whether and how to react. This is the same decoupling principle behind the Observer pattern from LLD Fundamentals, applied at the scale of services instead of objects.
Payload Design: Thin Reference vs. Full Snapshot
{"event_type": "order.updated", "order_id": 501}
// subscribers that need details must call back to fetch the current order{
"event_type": "order.updated",
"order_id": 501,
"status": "shipped",
"total": 149.99,
"items": [{"product_id": 42, "quantity": 2}]
}
// subscribers get everything they likely need without an extra round tripA thin event keeps the payload small and avoids ever shipping stale data (subscribers always fetch current state when they act), at the cost of an extra round-trip API call for every subscriber that needs details. A full-snapshot event avoids that round trip but risks the payload becoming stale by the time a subscriber processes it (especially under retry or delayed delivery), and it couples every subscriber to the exact shape of the snapshot the publisher chose to include. Neither is universally correct - the choice depends on how many subscribers typically need the detailed data and how tolerant they are of slightly-stale values.
An Event Catalog
As a system accumulates dozens of event types across many services, an explicit, documented event catalog - what events exist, their exact payload schema, who publishes each one - becomes as important as REST's resource documentation or a GraphQL schema's self-describing types. Without it, discovering "does an event already exist for this" becomes tribal knowledge, and teams end up publishing near-duplicate events because nobody could find the existing one.
Every event should carry a unique `event_id` (distinct from the business entity's own ID, like `order_id`) - this is what allows the exactly-once/idempotent-consumer patterns covered later in this module to detect and safely ignore a duplicate delivery of the same event.
Interview Signal is part of Pro
See a real weak answer next to a real strong one for this exact topic.
Quiz is part of Pro
Test what you just read with a short quiz, and bank the XP.
Design Event Storm in the API Design Lab's gRPC & Event-Driven act.