Explainer

Event-Driven Architecture Explained Simply

Event-driven architecture lets services react to facts instead of calling each other directly. How it works, the four patterns, and why Netflix runs a trillion events a day.

By Ricardo de Jong 10 min read 11:35 video

Watch the explainer

Picture two restaurants. In the first, the waiter walks to the kitchen, stands at the counter, and asks the chef “is the order ready?” every ten seconds. He is blocked, waiting, while three other tables try to flag him down. That is how most software is built: one service calls another, waits for a reply, and hopes nothing breaks in between.

Now picture the second restaurant. The chef finishes a plate, sets it on the counter, and rings a bell. Any free waiter grabs it. The chef does not care which one, and the waiter does not care which chef cooked it. Nobody blocks anybody. That second kitchen is event-driven architecture, and the biggest engineering teams on the planet run on it. This guide covers what it is, how it works, the patterns people confuse, and where it quietly falls apart.

What is event-driven architecture?

Event-driven architecture is a design approach where components communicate by producing and reacting to events, immutable records of something that already happened, instead of calling each other directly. Instead of OrderService calling InventoryService, the order service fires an OrderPlaced event and any service that cares decides how to react. Martin Fowler calls this reversal the dependency switch.

That switch is the whole idea. In a normal request, the caller depends on the callee: it has to know the other service exists, where it lives, and what it expects. Flip it, and the producer just broadcasts a fact into the system and forgets about it. New consumers can hook onto that fact later without anyone touching the producer.

Request / responsetight
Order service Payment service Inventory ✕ down one fails, all fail

A waits on B waits on C. The caller must know each callee, and a failure at the bottom cascades to the top.

Event-drivenloose
Order service EVENT BUS · OrderPlaced Payment Inventory Email one fails, the rest carry on

The producer announces a fact and forgets it. Each consumer decides whether to care. Add a fourth without touching the first.

Fig. 1 The dependency switch. On the left, each service waits on the next and a failure at the bottom climbs back to the top. On the right, the producer emits one fact and three consumers react on their own, so losing one does not stop the rest.

This decoupling happens on three axes at once. Producers and consumers are decoupled in identity (the producer does not know who receives the event), in time (the consumer can process it later), and in space (a broker handles the routing). Take those three away and you are back to one service phoning another.

The problem EDA was built to solve

The pain starts with coupling. In a request-response system, Service A calls Service B directly, so both have to be online at the same moment, A has to know exactly where B lives, and if B goes down, A goes down with it. Failures cascade. Now multiply that by a hundred services and every new feature becomes a negotiation with every team you depend on.

This is the wall LinkedIn hit in the late 2000s. Activity streams, metrics, and logs all needed to reach dozens of downstream systems at once: fraud detection, job matching, machine-learning models, the newsfeed, data warehouses. The existing tools could not keep up with the growth, so LinkedIn built Kafka, and the idea of treating messaging as a durable, append-only log spread from there.

The fix is to stop wiring services to each other and wire them to a shared stream of events instead. A team can drop a new consumer onto the stream without asking permission, scale it independently of everything else, and survive a producer being briefly offline. You trade a tidy call chain for a loosely joined mesh, and at a certain size that trade becomes the only thing that works.

How does event-driven architecture work?

It works by moving event notifications through a broker. Here is the distinction most tutorials skip: an event is the immutable fact, but what actually travels across the network is an event notification, a message carrying the data and metadata about that change. Developers usually pick one of two flavors. State-carrying events put everything the consumer needs in the payload, so it never has to call back. Identifier events carry just a reference ID, and consumers fetch the rest themselves.

Those notifications flow through three messaging models, and the difference between them matters more than the broker brand. Pub/sub is fan-out, where every subscriber gets a copy. A message queue is point-to-point, where each message goes to exactly one worker and is then gone. An event stream writes to a durable, ordered log that keeps events after they are read, which is Kafka’s core innovation and the thing plain pub/sub cannot do.

Fan-out

Pub / Sub

A publisher sends to a topic and every subscriber gets its own copy. One-to-many broadcast.

  • AWS SNS
  • Google Pub/Sub
  • MQTT
Point-to-point

Message queue

Each message goes to exactly one consumer, then it is gone. Many workers share the load.

  • RabbitMQ
  • Amazon SQS
  • ActiveMQ
Durable log

Event stream

grp A grp B

Events append to an ordered log and stay. Many groups read the same data and replay any point.

  • Apache Kafka
  • Pulsar
  • Kinesis
Fig. 2 The three messaging models. Pub/sub copies each event to every subscriber, a queue hands each message to one worker, and a stream keeps an ordered log that many consumer groups can replay. Real systems mix them.

These are not mutually exclusive, and the best designs combine them. Kafka acts as both an event stream and pub/sub through consumer groups: different groups each get the full feed, while consumers inside one group share the load. The classic AWS pattern pairs SNS for fan-out with SQS for a reliable queue per service. Pick the model that fits the job rather than forcing one everywhere.

The four EDA patterns developers confuse

Fowler identified four distinct patterns that people constantly blur together, and he warns that mixing them up causes real project failures. Each is a separate tool with its own cost. Knowing which one you are actually using, and which one you need, is most of the battle.

Event notification Minimal

Emit a thin event, usually just an ID and a type. Consumers call back to the source if they need the details. Lowest coupling, but the logic flow is invisible.

Event-carried state transfer Self-contained

Pack all the data a consumer needs into the payload, so it never calls back. Better resilience and latency, paid for with duplicated data and eventual consistency.

Event sourcing Log as truth

Store every change as an immutable event and derive state from the log. You get a full audit trail and can rebuild any past state by replaying it.

CQRS Split read / write

Separate the write model from the read model entirely, using events to sync them. Heavy read traffic never slows writes. Fowler warns it is easy to misuse.

Fig. 3 The four patterns from Fowler's 2017 article. They are not a progression or a stack: each solves a different problem, and the failure mode is using one while believing you are using another.

The split that bites hardest is event sourcing versus the rest. Event notification and event-carried state transfer are about how services talk to each other. Event sourcing is about how you store data, keeping the log of changes as the source of truth instead of just the latest value. CQRS then takes that further by giving reads and writes separate models. You can use any one without the others, and Fowler is openly wary of teams reaching for CQRS when they do not need it.

Event-driven architecture vs request-response

Neither approach wins outright; they answer different questions. Request-response is pull-based and synchronous, so the caller blocks until it gets an answer, which is exactly what you want for a user-facing query or a transaction that must confirm. Event-driven is push-based and asynchronous, fire-and-forget, which is what you want for high-throughput streams and background work. The table below is the short version teams actually reason with.

DimensionRequest / responseEvent-driven
CommunicationSynchronous, caller blocksAsynchronous, fire-and-forget
CouplingTight, caller knows calleeLoose, producer does not know consumers
Failure modeCascadingIsolated
ScalingCoupledIndependent per consumer
Data freshnessAlways currentEventually consistent
Tracing a flowOne explicit call chainImplicit, harder to follow
Best forQueries, transactional confirmationsData streams, background orchestration

The same logic answers the “EDA versus microservices” question people often ask. They are not competitors. Microservices are about splitting an app into independently deployable services; EDA is about how those services communicate. You can build microservices that call each other over REST, and you can fire events inside a single application. They pair well, but neither one requires the other.

Who runs event-driven architecture at scale?

The companies you would expect, at numbers that make synchronous calls impossible. LinkedIn, where Kafka was born, went from one billion messages a day in 2011 to seven trillion by 2019. Netflix processes over a trillion events a day through its Keystone platform. These are not pilots; they are the backbone.

1 trillion Netflix · events/day

Every play, pause, and skip is an event. Logging that synchronously would be a self-inflicted DDoS, so Netflix runs a streaming-first platform on Kafka and Flink and accepts a drop rate under 0.01%.

7 trillion LinkedIn · messages/day

Where Kafka was born. LinkedIn grew from 1 billion messages a day in 2011 to 7 trillion by 2019, across 100-plus clusters, 4,000 brokers, and 7 million partitions.

15 min → sec Uber · freight latency

The ride lifecycle is inherently event-driven. Moving freight aggregation from batch jobs to Kafka and Flink cut latency from over fifteen minutes to seconds, across 1,000-plus downstream services.

6 million LMAX · orders/sec

The opposite extreme: a financial exchange processing 6 million orders per second on a single thread with the Disruptor ring buffer, with under 50 nanoseconds of inter-thread latency.

Fig. 4 Four production systems at the extremes. Each hero number is what makes centralizing impossible: at a trillion events a day, you cannot log synchronously, and at six million orders a second, you cannot afford a network hop.

The patterns inside each one are instructive. Netflix runs one consumer that watches infrastructure health and routes around failing CDN nodes, while a separate consumer reads the same stream for personalization, and it deliberately accepts a drop rate under 0.01% rather than ever risk playback. Uber processes trillions of messages across more than a thousand downstream services, and moving its freight aggregation off batch jobs cut latency from over fifteen minutes to seconds. At the far end sits LMAX Exchange, which runs its entire business logic as a single-threaded event-sourcing processor handling six million orders per second. Same model, wildly different scale.

The event-driven toolkit: Kafka, RabbitMQ, and the cloud

The tooling has matured to the point where the hard part is choosing, not finding. Apache Kafka 4.0, released in March 2025, removed ZooKeeper entirely, the most significant architectural change in its history. Its KRaft metadata layer is now the only option, recovers roughly ten times faster, and scales toward millions of partitions. Kafka is the default when you need a durable, replayable log at high throughput.

RabbitMQ is the better fit for complex routing at moderate volume, now on version 4.x with native AMQP 1.0 and Raft-based quorum queues. Apache Pulsar leans on built-in multi-tenancy and geo-replication, while NATS is the featherweight option, a single Go binary using around twenty megabytes of RAM. On the cloud side, AWS offers EventBridge, SNS, SQS, and Kinesis; Azure has Event Grid and Kafka-compatible Event Hubs; and Google Cloud Pub/Sub stands out for exactly-once delivery at general availability.

The standards layer is where things are quietly converging. CloudEvents, a CNCF project that graduated in January 2024, gives you a universal envelope so an event from one system is legible to another. The commercial center of gravity is shifting too: in December 2025, IBM agreed to acquire Confluent, the company founded by Kafka’s creators, for around 11 billion dollars, a sign of how foundational streaming infrastructure has become.

Where does event-driven architecture fall short?

Its biggest weakness is the flip side of its biggest strength. The same decoupling that isolates failures also hides the flow of logic, and this is where most EDA writing goes quiet. In a synchronous system you can follow a request through one call chain. In EDA, one user action can fan out across dozens of services, and Fowler calls this the dark side: there is no single program text showing the complete flow.

Observability The "dark side"

One user action can cascade across dozens of services, with no single program text showing the flow. You need distributed tracing and correlation IDs from day one.

Eventual consistency Stale for a moment

A user may place an order and briefly see old inventory. Fine for most apps, wrong for a bank balance before a withdrawal. That is a design choice, not a bug.

Schema evolution Events are contracts

Change a field and you break every consumer reading it. Use Avro or Protobuf with a schema registry, add only optional fields, and never delete a required one.

Distributed monolith The trap

Throwing events on a broker does not make a system loosely coupled. Thick consumers wired to specific events are a monolith with extra network hops.

Fig. 5 The four sharp edges. None of these is a reason to avoid EDA, but each is a tax you pay whether you planned for it or not. Observability and idempotency in particular have to be designed in from day one, not bolted on.

There is one more edge the diagram only hints at: idempotency. Most brokers deliver at-least-once, which means your consumers will receive duplicate events, so every consumer has to handle them safely or you get subtle bugs like double billing. Pair that with the distributed-monolith trap, where thick consumers wired to specific events recreate a monolith’s rigid dependencies over the network, and you have the two mistakes that turn an EDA migration sour.

When should you use event-driven architecture?

Reach for it when you have high-throughput data streams, many independent consumers of the same facts, or services that need to scale and fail apart from each other. That is the sweet spot: real-time reactivity, loose coupling, and the ability to add consumers without redeploying producers. If your problem looks like LinkedIn’s fan-out or Netflix’s telemetry firehose, this is the right tool.

Skip it just as deliberately. Simple CRUD apps do not need it. Flows that demand strong consistency, like checking a bank balance before a withdrawal, are better served by a synchronous call that confirms. Small teams often find the operational overhead, the tracing, the schema registry, the dead-letter queues, outweighs the benefit. And if a problem does not need asynchronous processing at all, adding events only buys extra latency and failure modes for nothing.

When you do start, learn three things before production: idempotency, so reprocessing an event changes nothing; the transactional outbox pattern, so a database write and its event succeed or fail together; and dead-letter queues, so one poison-pill message does not stall the pipeline. RabbitMQ is the gentlest on-ramp for messaging basics, and Kafka 4.0 now runs from a single container with no ZooKeeper to babysit.

Event-driven architecture is not a silver bullet. You give up immediate consistency and simple tracing, and in return you get loose coupling, independent scaling, and systems that do not topple when one piece fails. The biggest teams in tech already settled the question of whether to use it. The real work is deciding which patterns fit your problem and where the boundaries belong.

Watch the 12-minute explainer

For the animated walk through the restaurant analogy, the four patterns, and the real-world systems, watch the full explainer on YouTube.

Frequently asked questions

What is event-driven architecture in simple terms?

Event-driven architecture is a way of building software where services announce that something happened, like "an order was placed", instead of calling each other directly. Any service that cares can react on its own. The producer never knows who is listening, which keeps the parts loosely coupled and independently scalable.

What is the difference between an event and a message?

An event is an immutable fact about something that already happened, written in the past tense, like "OrderPlaced". A command tells a specific service to do something, like "PlaceOrder". A message is the envelope that carries either one across the network. Confusing a command for an event is how loosely coupled designs quietly become tightly coupled.

What are the four event-driven architecture patterns?

Martin Fowler named four: event notification (a thin event, call back for details), event-carried state transfer (the payload holds everything), event sourcing (the event log is the source of truth), and CQRS (separate read and write models). Mixing them up is a common cause of failed projects, so it helps to know which one you are using.

Is event-driven architecture the same as microservices?

No. Microservices are about splitting an application into independently deployable services. Event-driven architecture is about how those services communicate. You can build microservices that call each other synchronously over REST, and you can use events inside a monolith. They pair well, but one does not require the other.

Is Kafka required for event-driven architecture?

No. Kafka is the most popular event-streaming platform, but event-driven architecture is a design approach, not a product. You can implement it with RabbitMQ, AWS EventBridge, Google Pub/Sub, NATS, Redis Streams, or plain webhooks. Kafka shines when you need a durable, replayable log at high throughput, but plenty of systems never need that.

When should you not use event-driven architecture?

Skip it for simple CRUD apps, for flows that need strong consistency like a bank balance check before a withdrawal, and for small teams where the operational overhead outweighs the gains. If a problem does not need asynchronous processing, adding events only buys you extra latency and failure modes for nothing.

Sources

  1. Martin Fowler · What do you mean by 'Event-Driven'? · retrieved 2026-06-20
  2. LinkedIn Engineering · Apache Kafka for 7 trillion messages per day · retrieved 2026-06-20
  3. Netflix Technology Blog · Keystone Real-time Stream Processing Platform · retrieved 2026-06-20
  4. Uber Engineering · Disaster Recovery for Multi-Region Kafka · retrieved 2026-06-20
  5. Martin Fowler · The LMAX Architecture · retrieved 2026-06-20
  6. Apache Kafka · 4.0.0 Release Announcement (ZooKeeper removed) · retrieved 2026-06-20
  7. Confluent · IBM to Acquire Confluent · retrieved 2026-06-20
  8. CloudEvents (CNCF) · A specification for describing event data · retrieved 2026-06-20
  9. AWS · What is an Event-Driven Architecture? · retrieved 2026-06-20
</>

Ricardo de Jong

Creator of Devsplainers

Ricardo de Jong makes Devsplainers, turning complex developer and AI topics into short animated videos and written companions. Each article is built from the same research and script behind the video. No hype, no jargon walls.

The newsletter

Liked this? Get the Take-Outs.

One email every Tuesday: a spicy take on a trending dev topic, video out-takes, and the tool of the week. Free.

Subscribe
<devsplainers>