What is Event-Driven Architecture?
This guide explains Event-Driven Architecture (EDA): systems that talk to each other in events instead of calls. It covers how EDA differs from Event Sourcing, the common styles of events between systems, and what it takes to make such an architecture work.
In Event Sourcing, events are the memory of a system: it stores what happened and derives its state from it. In Event-Driven Architecture, events are the communication between systems: one system announces what happened, and others react to it. The two ideas are independent – a system can use one without the other – but they complement each other well, because a system that already records its events has something worth telling others.
From Calls to Events#
In a call-based architecture, a system that needs something from another system asks for it: it calls an API and waits for the answer. When a book is borrowed in a library, the lending system would call the membership system to update the reader's loans, the catalog to mark the copy as unavailable, and the notification service to send a confirmation – and it would have to know about all three.
In an event-driven architecture, the lending system announces what happened: a book was borrowed. Each of the other systems listens and decides for itself how to react. The lending system does not know who listens, and it does not wait for anyone.
This separates deciding from reacting:
- The system that owns a process decides what happened and records it.
- Other systems decide how to respond, each according to its own responsibility.
New reactions – analytics, a loyalty program, a fraud check – can be added without touching the system that produces the events.
What Changes, and What Does Not#
Event-driven communication decouples systems in several ways:
- In time. The producer does not wait for its consumers, and a consumer that is down can catch up later.
- In knowledge. The producer does not know its consumers, so it does not have to change when a new one appears.
- In load. Each consumer processes events at its own pace.
What it does not remove is the dependency on meaning. Consumers rely on what an event says and on the shape of its data. A published event is a contract, and changing it carelessly breaks others just as surely as changing an API – see Domain Events and Integration Events.
It also changes how consistency works. When the membership system learns about a loan a moment after it happened, the systems are eventually consistent: for a short time, they disagree. This is rarely a problem in practice, but it has to be designed for – see Eventual Consistency in Practice.
Styles of Events Between Systems#
Not all events that cross a system boundary carry the same amount of information. Two styles are common:
- Event notification. The event says that something happened and carries little more than a reference – book 42 was borrowed. A consumer that needs details asks the producer. The events stay small, but consumers depend on the producer being available.
- Event-carried state transfer. The event carries the data consumers need – book 42 was borrowed by reader 17 until March 23. Consumers can act without asking back and can keep their own copy of the data they care about. The events are larger, and the data they carry becomes part of the contract.
Neither is better in general. Notifications suit consumers that need little or change often; state transfer suits consumers that need to work independently of the producer. Many systems use both.
Choreography and Orchestration#
When a business process spans several systems, there are two ways to coordinate it:
- Choreography. Each system reacts to events and emits new ones, and the process emerges from these reactions. There is no central coordinator, which keeps the systems independent – but the process as a whole is not written down in any single place.
- Orchestration. One component knows the process and tells the other systems what to do, often by sending commands and waiting for their events. The process is explicit and easy to follow – but the orchestrator depends on everyone it coordinates.
Choreography works well for short, loosely related reactions. For long processes with many steps, deadlines, and compensations, an explicit orchestrator is often easier to understand and to change.
Push and Pull#
Events can reach their consumers in two ways. With push, a broker or the producer delivers events to subscribers. With pull, consumers read the events from an ordered log at their own pace and remember how far they have come.
Pulling from an ordered log has a useful property: a new consumer can start from the beginning and process the entire history, not just what happens from now on. The consumer side of this – remembering the last processed event, idempotency, and parallelization – is described in Building Event Handlers. How to make sure events reliably leave the system that produced them is the topic of Reliable Delivery.
Making It Work#
Event-driven architectures are easy to start and easy to get lost in. A few practices keep them manageable:
- Name events after facts in the domain. An event such as
book-borrowedtells every consumer what happened; an event such asloan-record-updatedonly tells it that something changed. - Use a common envelope. A shared format for the metadata of events – source, type, time, identifier – makes events from different systems look alike and makes tooling reusable – see CloudEvents.
- Make flows traceable. Carry a correlation identifier from the event that started a process through every event it causes, so that a process spanning several systems can be followed afterwards.
- Document who publishes what. Without a place that lists which events exist, who produces them, and what they mean, an event-driven landscape turns into a tangle nobody fully understands.
When to Use It#
Event-Driven Architecture pays off where several systems need to react to the same facts, where systems are owned by different teams, and where availability matters more than immediate consistency across system boundaries. It is less suitable where a caller genuinely needs an answer right away – checking whether a reader is allowed to borrow at all is a question, not an event.
Used where it fits, it lets systems grow independently while staying connected through the one thing they share: what actually happened.