Event Notification vs Event-Carried State Transfer
What This Concept Is
Once you have decided something is an event, a second question appears: how much does the event carry? Fowler's two-lens split is the clearest framing:
Event notification
A thin event. It says "something happened" and carries only what identifies it: IDs, timestamps, maybe a small discriminator. Consumers who want details call back to the producer.
{
"event_type": "OrderPlaced",
"event_id": "01HX...",
"occurred_at": "2026-04-22T14:11:03Z",
"order_id": "ord_9f2a"
}
Consumer flow: receive -> HTTP GET to /orders/ord_9f2a -> act on the response.
Event-carried state transfer (ECST)
A fat event. The event carries enough state for the consumer to act without calling back. The consumer can store or project this state locally and serve its own reads.
{
"event_type": "OrderPlaced",
"event_id": "01HX...",
"occurred_at": "2026-04-22T14:11:03Z",
"order_id": "ord_9f2a",
"customer_id": "cus_4b8c",
"customer_email": "a@b.com",
"items": [{"sku": "SKU-42", "qty": 2, "unit_cents": 1999}],
"total_cents": 4299,
"currency": "USD",
"shipping_address": {...}
}
Consumer flow: receive -> act directly -> maybe update a local materialized view.
These are two points on a spectrum. Many real events sit in between.
Why It Matters Here
This choice determines coupling, latency, and failure behavior:
| Axis | Notification | ECST |
|---|---|---|
| Coupling | Consumers couple at API shape (callback endpoint) | Consumers couple at event schema |
| Availability | Producer must be up for the callback | Producer can be down; consumers still work |
| Latency under load | Each event = one extra synchronous call | No callback; consumer acts immediately |
| Data freshness | Always fresh (read-through) | Stale between events |
| Payload size / broker cost | Tiny | Can be large; think carefully about retention |
| PII / leakage risk | Low (consumer authenticates per call) | High (sensitive data lands in many consumer DBs) |
Concrete Example
Same domain (OrderPlaced), two different subscribers. Which style?
Notification is right for audit: it only needs to know an order happened and pull the details lazily if/when audited. Payload on the topic is tiny.
ECST is right for notifications: the email worker cannot afford to be blocked by the order service being down at 3 a.m. Carry the customer email and a short summary on the event itself.
ECST with a cached view is right for analytics: it folds the events into a materialized view so it can answer "orders per minute" without calling anyone.
Notification is right for support: support dashboards load fresh data on demand; serving stale data is worse than a small synchronous read.
Same topic, different subscriber consumption strategy. Fowler's observation stands: "event" alone does not tell you the shape.
A Third Variant: Hybrid
Carry the "core" facts (IDs, timestamps, primary identifiers) and enough denormalized fields that most consumers do not need to call back. Send-once, rarely-change data travels fat. Volatile or secondary data stays thin and is fetched on demand.
A rule that works in practice: if most consumers ask the same follow-up question, hoist that field onto the event.
Common Confusion / Misconception
"Bigger events are always better -- skip the callback." ECST creates a data-coupling tax: every consumer that stores fat events becomes a mini-copy of your producer's model. Schema changes propagate. Stale data accumulates. PII spreads. For hot, frequently mutated data, lean thinner.
"Notification is always safer -- consumers can just call back." Callbacks couple you to the producer's availability. If the producer is down, every subscriber is degraded. For critical paths (order confirmation emails, billing) you often want ECST specifically so the system keeps running when the producer is sick.
"The event schema should reflect the DB schema." Treat the event as a contract. Denormalize for consumers, hide internal fields, and version it. The event is not your data model leaking onto a bus.
"Only one of these is real event-driven." Both are. Fowler's four lenses (notification, state transfer, sourcing, CQRS) overlap; teams mix. Do not tie yourself in knots over which is "correct."
How To Use It
Per-event decision guide:
Design rules:
- Version your event schema. Whichever lens you pick, the schema will change; pretend it is a public API.
- Do not put secrets on the event. Passwords, full PAN, access tokens never ride the bus. IDs travel; tokens fetch.
- Bound the size. ECST events over ~100 KB indicate a modeling problem; the event is probably two events.
- Document the lens per topic. "This is a notification topic; consumers must call back for details." Prevents accidental drift.
Check Yourself
- Define both lenses in one sentence each without looking.
- Why does ECST improve availability and hurt schema stability at the same time?
- Name one domain (finance, healthcare, messaging) where ECST is dangerous and explain why.
Mini Drill or Application
Pick three events from a system you know. In 20 minutes, for each:
- Write the notification-style payload (just IDs).
- Write the ECST-style payload.
- List each subscriber you can think of and decide which lens they want. If subscribers split, is the event really one event or two?
- Note one field that is sensitive and justify keeping it off the event entirely.
Transfer to Adjacent Domains
- Availability engineering (S8M1). ECST is a deliberate availability trade: you accept stale reads and schema-change coupling in exchange for the consumer staying alive when the producer is down. Notification trades the opposite way. The choice is an explicit availability-vs-freshness knob.
- Schema governance. ECST events are public contracts with many downstream copies of the payload. That is why event schemas with a registry (Avro/Protobuf + Confluent Schema Registry) dominate in ECST-heavy shops; notification-style topics can often survive with lighter discipline.
- Privacy / GDPR. ECST spreads PII to every subscriber's datastore. Notification keeps PII behind an authenticated callback. In regulated industries the lens choice is sometimes made for you by the compliance team, not the architects.
- Event sourcing (Concept 13). An event-sourced aggregate's internal events are naturally fat (full state transitions), but what you publish to the world is often a notification or a deliberately minimal ECST variant. "Internal event, external event" is the canonical boundary.
Read This Only If Stuck
- Richards & Ford: Asynchronous Capabilities -- the async posture that makes either lens viable
- Richards & Ford: Preventing Data Loss -- durability considerations that matter more as events get fatter
- Richards & Ford: Event-Driven Architecture Style -- broker topology that both lenses ride on
- System Design Primer: Availability patterns -- the availability math ECST leans on (consumer keeps running when producer is sick)
- System Design Primer: Consistency patterns -- eventual-consistency vocabulary for stale ECST-derived state
- Martin Fowler: Event-Carried State Transfer -- the source of the term, with explicit tradeoffs
- Martin Fowler: Event Notification -- the other half of the same essay
- Martin Fowler: Domain Event (EAA) -- the older "publish a fact" treatment that informs both lenses
- Confluent: Schema Registry overview -- the operational backbone ECST usually needs
- Enterprise Integration Patterns: Document Message -- EIP's name for ECST-shaped messages; useful historical framing