Why Adding Kafka Can Make Your System Worse
Kafka is powerful, but powerful doesn't mean necessary. Why reaching for an event bus before the problem demands one often trades a simple bug for a distributed system to operate.
- Production Lessons
- Kafka
- Event-Driven Architecture
- Software Architecture
- Distributed Systems
I've seen this architecture decision go wrong more than once: "This needs to scale. Let's put Kafka in the middle."
It sounds like a good decision. Until the system becomes harder to operate than the problem it was supposed to solve.
Suddenly you have producers, topics, partitions, consumer groups, offset management, retries, dead-letter handling, schema evolution, monitoring, and replay strategies to maintain — for a problem that might have been solved with a database transaction and a background worker.

That's the uncomfortable truth about event-driven architecture. Kafka is powerful. But powerful doesn't mean necessary.
Before introducing an event stream, I ask:
- Does the producer really need to be decoupled from the consumer? If not, a direct call may be simpler.
- Do we need independent consumers? If only one service reacts, an event bus may add unnecessary complexity.
- Do we need replayable history? If not, a simpler queue may be enough.
- Can the team operate it reliably? Architecture isn't just about runtime performance — it's also about operational ownership.
This is where experienced engineers think differently. Junior thinking asks: "What technology can solve this?" Senior thinking asks: "What's the simplest architecture that satisfies the requirement?"
Event-driven architecture can give you decoupling, independent scaling, asynchronous processing, replayability, and multiple consumers. But you also pay for eventual consistency, operational complexity, debugging difficulty, duplicate processing, ordering problems, and schema evolution.
So the lesson isn't "don't use Kafka." It's: Don't introduce distributed complexity until the problem actually requires it.
The best architecture isn't the one with the most infrastructure. It's the one with the fewest moving parts that can still handle the future you actually need.
What's the most over-engineered component you've seen added to a production system?
Keep reading
Why Great Systems Don't Make You Wait for Everything
Order confirmation shouldn't wait on payment, inventory, email, and analytics to all finish. How separating the critical path from everything else keeps event-driven systems responsive.
Why the Biggest Production Mistake Is Trying to Say Yes to Every Request
Trying to process every request immediately is often what takes a system down, not the traffic itself. Why resilient systems reject, throttle, and shed load instead of pretending capacity is infinite.
Why Some Systems Crash at 1,000 Users While Others Handle Millions
A system doesn't become slow because more users arrive — it becomes slow because one component reaches its limit. Traffic exposes bottlenecks; it doesn't create them.