The Shift from CRUD to Events
What This Concept Is
A CRUD system stores current state and exposes Create, Read, Update, Delete. An event-driven system stores (or publishes) the history of changes -- the events -- and treats the current state as a projection of that history.
The pivotal move is this:
The database row is not the truth. The row is the latest answer produced by the sequence of facts.
Once you internalize that, several things stop being magic:
- audit trail is free; it was the log all along
UPDATE users SET email = ?quietly erases the factEmailAddressChanged, which many downstream systems actually wanted- time travel ("what did this customer look like on March 1?") is a query over history, not a debate with the DBA
- multiple consumers can materialize their own views of the same history instead of synchronously reading the same row
You do not have to go full event sourcing (Concept 13) to benefit. Even without rewriting your database, publishing events on every state change lets other services react without polling your tables.
Why It Matters Here
Event-driven architecture is, at root, a bet that change is a first-class thing worth naming. CRUD treats change as invisible: the new value overwrites the old, nobody is told, and if anyone else needs to know they have to poll, subscribe via CDC, or be told out-of-band.
Once you make change visible -- by emitting an event for every meaningful transition -- the rest of this module falls into place:
- pub-sub (Cluster 2) has something meaningful to publish
- brokers (Cluster 3) have something worth retaining
- workflows (Cluster 4) can be driven by event progression instead of by a request graph
- sourcing and CQRS (Cluster 5) become available design choices
Concrete Example
CRUD view
users table
+---------+----------+----------+-------------------+
| user_id | name | email | updated_at |
+---------+----------+----------+-------------------+
| u_123 | Priya K | p@b.com | 2026-04-22 14:02 |
A week later:
| u_123 | Priya K | p@c.com | 2026-04-29 09:17 |
Questions the CRUD system cannot answer:
- what was the email on 2026-04-23?
- why did it change?
- who needs to be told that it changed?
- did it change once, or did someone change it to
p@x.comand then back?
Event-driven view
events stream for user u_123
+-------------------+-------------------+-------------------------+
| occurred_at | event_type | payload |
+-------------------+-------------------+-------------------------+
| 2026-04-22 14:02 | UserRegistered | {name, email: p@b.com} |
| 2026-04-26 10:44 | EmailChangeReq. | {new_email: p@x.com} |
| 2026-04-26 10:47 | EmailChangeReq. | {new_email: p@c.com} |
| 2026-04-29 09:17 | EmailAddressCh. | {new_email: p@c.com} |
Now:
- the current email is the last
EmailAddressChanged:p@c.com - on 2026-04-23 it was
p@b.com-- read forward until that date - billing service subscribes to
EmailAddressChangedand updates its own mailing list without polling your DB - the analytics team can detect the "user tried
p@x.combut landed onp@c.com" pattern
The CRUD row is still fine as a view. It is no longer the truth.
What This Is Not
This concept is not "use events instead of a database." Most systems keep a database -- the event publication is additional, and (if you use the outbox pattern, Concept 06) it is published atomically with the DB write. This concept is also not "event sourcing." Event sourcing (Concept 13) is the strong form: the log is the only source of truth and the DB, if any, is derived. You can adopt the mental shift (events are first-class) long before you adopt the strong form.
Common Confusion / Misconception
"CRUD is wrong." CRUD is fine for simple masters-and-details data. The shift matters where change is interesting -- domain events like orders, payments, shipments, support cases, policy updates. A lookup table of country codes does not need an event.
"We emit an event after every UPDATE, so we are event-driven now." Emitting an event after the fact leaves the dual-write bug (Concept 06). Also, not every UPDATE is a domain event: bumping updated_at is not EmailAddressChanged. Name events by the domain transition, not by SQL.
"Change data capture (CDC) is the same thing." CDC publishes row-level changes directly from the database log. It is useful, but it leaks your schema to consumers and names events by tables and columns (users.email updated), not by domain (EmailAddressChanged). CDC is a tool; the shift in this concept is semantic.
"We will just keep history in an audit table." You can, and in many shops that is the starting point. The limitation: audit tables are read-only historical records used by humans. Events are consumed by other systems and drive their behavior. Different use, different shape.
How To Use It
When you add or redesign a service, apply this exercise before any schema work:
- List the domain transitions (state changes) that are interesting to other services or people.
- Name each in past tense.
- For each, ask: if my DB did not exist and someone could only read this stream of events, could they reconstruct what they need?
- Decide per transition: event-only, DB-only, or both (via outbox).
Check Yourself
- Why is "the current row" a derived view and not the source of truth in event-driven thinking?
- Name three questions an event log answers that a CRUD table alone cannot.
- When is CRUD still the right default -- and why?
Mini Drill or Application
Pick a boring CRUD operation in a system you know (editing a user profile, reassigning a ticket, updating a product price). In 20 minutes:
- Write the SQL that would execute today (the
UPDATEstatement). - Write the domain event(s) that should accompany that update. Often the right answer is 1; sometimes there are 2 or 3 distinct transitions hiding in one
UPDATE. - For each event, list two services or analyses that would benefit from consuming it.
Transfer to Adjacent Domains
- Event sourcing (Concept 13). The strong form of this shift: the log is the only source of truth, and every DB is derived. Adopt the mental model now even if you never adopt the strong form; the shift is linguistic before it is architectural.
- Outbox pattern (Concept 06). The specific technique that lets you publish events atomically with DB writes -- it is how the CRUD-to-events shift becomes reliable without giving up your relational store.
- Data platform / lakehouse (S6). A domain-event stream is already the correct input for a lakehouse. Teams that still pipe raw CDC rows into Snowflake/Databricks and re-derive domain meaning downstream are paying the CRUD-shaped tax twice.
- CDC and
DEBEZIUM. Change data capture is a useful transport for this shift, but (as the misconception notes) CDC on its own leaks table shape. Pair CDC with an outbox table to keep the event contract clean. - Analytics maturity. Teams that can answer "what did we know on date X?" have usually already made this shift -- explicitly or by accident. If that question routinely requires a database snapshot restore, you are still CRUD-shaped.
Read This Only If Stuck
- Richards & Ford: Event-Driven Architecture Style -- the request-based vs event-based contrast
- Richards & Ford: Asynchronous Capabilities -- async posture that the shift naturally produces
- System Design Primer: Asynchronism -- message-queue framing that makes the CRUD-to-event shift operational
- System Design Primer: Consistency patterns -- eventual-consistency vocabulary you need once the row is no longer the truth
- Martin Fowler: Event-Driven State -- the "event-carried state transfer" and "event sourcing" lenses of Fowler's four-lens essay
- Martin Fowler: Reporting Database -- the "read DB is derived, write DB is canonical" stance; a halfway house on the way to full event-sourcing
- Debezium: Outbox event router -- the production CDC implementation that makes the shift safe in relational systems
- Confluent: It's Okay To Store Data In Kafka -- the case for the log as a durable system of record; underpins the "row is derived" framing
- Martin Kleppmann: Turning the Database Inside Out -- lecture that reframes the DB as a cache of the log (50 min; skim the first 20)
- Kleppmann: Stream processing, Event sourcing, Reactive, CEP… -- essay that places the CRUD-to-events shift in the wider landscape of data paradigms