Why You Need an Outbox Pattern (Even If Your Event Bus Is Fancy)

Walter SotoWalter Soto
3 min read

The Fantasy of Distributed Systems

You built your distributed system, hooked it up to Kafka or NATS or RabbitMQ, and now everything talks to everything else like some perfectly choreographed dance. At least that's what the architecture diagram suggests.

In practice, things fall apart in much smaller, more pathetic ways. A server restarts. A pod crashes. Some timeout fires a little too early. And right in the middle of that, your app writes something to the database but never sends the event to the bus. Or worse, sends the event but fails to commit the database. Congratulations, you're now the proud owner of an inconsistent system.

The Problem Nobody Wants to Talk About

You may hear people argue that their event bus has built-in guarantees. Sure. They’ll talk about at least once delivery, idempotency, eventual consistency, and a bunch of other words that sound smart enough to end conversations. But none of those solve the core problem if your app crashes between writing the database and sending the event. You need something that guards the gap.

Distributed systems don't care how good your intentions are. They reward paranoia and punish optimism.

Enter the Outbox Pattern

The basic idea isn't complicated: instead of writing to your database and your event bus as two separate actions, you write both the data and a corresponding event into the same database transaction. That outbox table is now your source of truth. A separate worker process reads from it and publishes events to your fancy bus. If the database commit succeeds, the event will eventually be processed. If not, it never existed to begin with.

It's not magic. It's paperwork. But paperwork keeps the lights on.

The Trade-Off

Of course, this means adding another moving part. Now you have an extra table, a poller, retries, and monitoring for the poller. But you're trading a sharp random failure for a boring, predictable system. If something breaks, you know where to look. You know which events didn't get published. And you have full control to replay or reprocess them.

The alternative is hoping your event publishing code never fails at exactly the wrong moment. It will. Eventually. You might not even notice until a customer calls support and asks why their account was never fully created. Then you'll pull logs, stare at gaps in your Kafka topic, and wish you'd just set up the outbox in the first place.

Why You Should Use It

The outbox pattern doesn’t eliminate failure. Nothing does. What it gives you is a system where failure is contained, observable, and recoverable. When the outbox poller stops, you see it. When events get stuck, you can replay them. When something downstream breaks, at least you know the events were captured.

You can build a system that tolerates mistakes, or you can build one that assumes nothing will go wrong. Only one of those is still standing after six months in production.

Conclusion

So yeah, your event bus is great. Keep it. You can wrap it in an outbox pattern, or go the CDC route, but that’s another discussion. Right now, we’re here for the outbox. It’s the seatbelt your system quietly hopes you’ll never need.

0
Subscribe to my newsletter

Read articles from Walter Soto directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Walter Soto
Walter Soto