Two Ways to Say “Something Happened”
NOTIFICATION (thin event):
{event: "OrderPlaced", order_id: 42}
consumers must CALL BACK to orders service for details:
[orders]──event──►[email svc]──GET /orders/42──►[orders]
extra hop, extra load, coupling returns ✗
STATE TRANSFER (fat event):
{event: "OrderPlaced",
order: {id: 42, items: [...], total: 89.90,
address: {...}, customer: {...}}}
[orders]──event+data──►[email svc] everything needed, local ✓
the fat event REPLICATES the relevant state to every subscriber —
each consumer becomes self-sufficient.
What It Buys You
□ NO CALLBACK COUPLING: email service never imports/calls
orders API. deploy/scale/fail independently. real decoupling.
□ LOCAL QUERIES: consumers build read models directly from
events — no synchronous fetches in their hot paths
□ RESILIENCE: orders service down? consumers process backlog
with data IN HAND. no blocked callbacks.
□ HISTORY IS COMPLETE: replay reconstructs full state
(event-sourcing friendly by construction)
The Costs to Weigh
- EVENT SIZE: every item list, address, price ships N times
(once per consumer group). bandwidth + broker storage multiply.
- FRESHNESS OF THE COPY: subscribers see state as of publish;
acting on stale copies is possible → version fields help
- PRIVILEGED DATA LEAKAGE RISK: carrying customer PII to the
analytics topic it doesn't need? scope payloads per audience:
full-fat for fulfillment; slimmed for analytics
- SCHEMA SURFACE GROWS: more fields = more evolution care
Sizing Guidance
| Data | Recommendation |
|---|---|
| Small core fields (<1KB) | carry always |
| Medium blobs | carry if ≥2 consumers need them |
| Huge payloads (images/docs) | claim-check pattern: store ref, carry pointer |
| PII-sensitive slices | separate topics per audience |
CLAIM-CHECK: {order_id, details_uri: "s3://..."} —
hybrid when payloads balloon. classic and effective.
When to Choose Which
THIN notification fits:
- rare consumers (1), or all consumers will call back anyway
- payload huge and single-consumer (claim-check territory)
- strict freshness: consumer MUST see current state
FAT state-transfer fits:
- multiple independent consumers (the common case!)
- replay/read-model building desired
- decoupling is a stated architectural goal
default in microservice estates: FAT for domain events,
thin for high-frequency telemetry. decide per stream, write it down.
Interview Framing
“Orders service publishes events consumed by 5 teams — what’s in the payload?” scored answer: name both styles, recommend state-transfer for this fan-out shape WITH reasoning (no callback re-coupling), address size/PII scoping per audience, claim-check escape hatch for blobs. This question tests whether your “events” are actually useful or just IDs requiring everyone to call you back — the thing EDA was supposed to prevent.
Premium Content
Unlock Event-Carried State Transfer and all premium lessons with a subscription.
All premium lessons
Ad-free experience
Priority support
From ₹199.99/year — See plans