80/20 Of The Week … The Outbox Pattern
Posting this because recently I talked about this a fair bit lol… now…
One of the most common problems in backend systems sounds simple:
How do you update the database and publish an event safely?
At first glance, it sounds easy.
You save the data, you publish the event and done.
Except… production systems don’t work that nicely.
- The problem
Imagine this flow:
Order gets created in the database, service then publishes OrderCreated event and at the end another service listens and starts payment, notification, shipping, etc…
Sounds fine.
But what if your service crashes after the DB write succeeds and before the event is published?
Now you have:
the order saved in the database but no event was sent and downstream services never find out about it
So your system is already inconsistent.
- Why naive solutions fail
A common first thought is:
“Fine, then publish the event first and save to the DB after.”
That just flips the problem.
Now the event might be published, but the database write may fail.
So consumers react to something that never actually became true in your system since you cannot roll back the event publish.
- The Outbox idea
The Outbox Pattern solves this by changing the flow.
Instead of doing: write business data publish event
you do this in the same database transaction:
write the business data and then write the event into an outbox table
That’s it.
So when an order is created, you also insert something like:
𝘦𝘷𝘦𝘯𝘵 𝘵𝘺𝘱𝘦 = 𝘖𝘳𝘥𝘦𝘳𝘊𝘳𝘦𝘢𝘵𝘦𝘥
𝘱𝘢𝘺𝘭𝘰𝘢𝘥 = 𝘰𝘳𝘥𝘦𝘳 𝘥𝘦𝘵𝘢𝘪𝘭𝘴
𝘴𝘵𝘢𝘵𝘶𝘴 = 𝘱𝘦𝘯𝘥𝘪𝘯𝘨
Both the business row and the outbox row are committed together.
Which means:
-
either both succeed
-
or both fail
- What happens next
A separate background process then:
reads pending events from the outbox table
publishes them to Kafka / RabbitMQ / whatever broker you use
marks them as processed
Basically don’t try to atomically update the DB and the broker directly.
Atomically update the DB and the intent to publish.
That intent lives in the outbox.
- Why it works
Because now your source of truth is consistent.
If the business transaction commits, the event is definitely recorded.
Even if the service crashes right after, the outbox processor can still publish it later.
So you don’t lose the event.
That’s the real strength of the pattern.
- But it’s not magic
Outbox is powerful, but it doesn’t make distributed systems “easy.”
You still need to think about:
duplicate delivery
the publisher may retry and send the same event more than once
idempotent consumers
consumers should handle duplicates safely
ordering
some event flows care about strict order, which can get tricky
cleanup
outbox tables grow, so retention/archiving matters
monitoring
if outbox publishing gets stuck, your system silently lags behind reality
So Outbox is not “problem solved forever.”
It’s more like:
problem moved into a safer and more controllable form
- Main takeaway
The Outbox Pattern is useful because it avoids this nightmare scenario:
DB updated successfully, event never sent.
And that exact failure mode is one of the most dangerous in event-driven systems, because it often looks fine at first…
until another service quietly stops reacting to reality.
Final thought
Outbox isn’t about fancy architecture.
It’s about respecting one uncomfortable truth:
the moment you mix database writes and broker publishes, partial failure becomes part of the design.
And Outbox is one of the cleanest ways to handle that.
#Backend #SystemDesign #DistributedSystems #Microservices #Kafka #Architecture #SoftwareEngineering
