almessadi.
Back to Index

Event Sourcing vs CRUD: Use It for Audit, Not for Aesthetics_

Event sourcing is powerful when history matters, but it adds real complexity. Use it where auditability and replay are core requirements.

PublishedMarch 22, 2024
Reading Time12 min read

Event sourcing gets oversold in two different ways.

One group treats it like the only serious way to model business systems. Another group dismisses it as architecture cosplay. Both are wrong.

Event sourcing is justified when the history of change is part of the business value, not just an implementation detail.

If all you need is a blog CMS or a straightforward admin panel, CRUD is usually the right abstraction. If you are building a ledger, an audit-heavy workflow, or a domain where reconstructing decisions matters, event sourcing becomes a serious option.

The Core Difference

In a CRUD model, the current row is the source of truth.

In an event-sourced model, the source of truth is an append-only stream of domain events, and current state is derived from those events.

That difference sounds small on paper. It changes a lot in practice.

A CRUD update:

UPDATE subscriptions
SET plan = 'pro', updated_at = now()
WHERE id = 'sub_123';

An event-sourced write:

{
  "type": "SubscriptionUpgraded",
  "subscriptionId": "sub_123",
  "previousPlan": "starter",
  "newPlan": "pro",
  "occurredAt": "2024-03-22T05:23:50Z"
}

The first statement tells you what is true now. The second tells you what happened.

That distinction matters when auditors, support staff, or downstream systems need the sequence, not just the result.

Why Teams Reach for It

Event sourcing earns its complexity when you need some combination of:

  • a strong audit trail
  • replayability
  • temporal queries such as "what did we believe yesterday?"
  • explicit domain events for downstream consumers

It is especially attractive when change history is a first-class business concept rather than an afterthought.

Why Teams Regret It

The cost is real:

  • you need projections for efficient reads
  • schema evolution becomes an ongoing concern
  • eventual consistency becomes part of the product experience
  • operational debugging gets harder

A CRUD system can often answer a support question with one query. An event-sourced system may require understanding the stream, the projection, and whether the projection is caught up.

That is why event sourcing should be chosen for a business reason, not because it feels more elegant.

The Read Model Is Not Optional

A pure event log is not a good general-purpose read store.

In real systems, event sourcing usually ends up paired with projections or CQRS-style read models:

type SubscriptionProjection = {
  id: string;
  currentPlan: string;
  status: "active" | "canceled";
  renewedAt: string | null;
};

async function handle(event: DomainEvent) {
  switch (event.type) {
    case "SubscriptionUpgraded":
      await db.query(
        `UPDATE subscription_projection
         SET current_plan = $2
         WHERE id = $1`,
        [event.subscriptionId, event.newPlan],
      );
      break;
  }
}

The event stream preserves history. The projection makes the system usable.

The Hard Parts Nobody Skips

If you adopt event sourcing, plan for these from day one:

Event versioning

Your understanding of the domain will change. Old events still need to be readable.

Idempotent consumers

Handlers must tolerate duplicate delivery or replay.

Projection rebuilds

You need a safe way to rebuild read models from the source stream.

Operational visibility

You need to know whether a projection is fresh, lagging, or broken.

None of that is theoretical. It is the daily operational surface of the system.

A Useful Decision Rule

Use CRUD when:

  • current state is what the business mainly cares about
  • audit can be handled with conventional logging
  • the domain is simple and query-heavy

Consider event sourcing when:

  • the sequence of change is itself valuable
  • correction and replay are core workflows
  • multiple downstream systems depend on domain events

This is not about architectural maturity. It is about fit.

Further Reading