Event-Driven Architecture Without the Kafka Hangover
Event-driven architecture gets conflated with "using Kafka" so often that it's worth separating the two. One is a design pattern. The other is a specific, heavyweight tool for a specific scale of problem.
What you're actually buying with Kafka
Kafka earns its complexity when you need durable, replayable, multi-consumer event logs at high throughput, with strict ordering guarantees per partition. That's a real and valuable set of properties. It's also not what most teams need on day one — and the operational cost (a cluster to run, partition rebalancing to understand, consumer group offset management to get right) shows up whether you've hit that scale yet or not.
The middle ground that gets skipped
Between "no events, just synchronous calls" and "full Kafka cluster," there's a wide, underused middle:
- A Postgres-backed outbox table with a polling worker, for teams that need reliable at-least-once delivery without a new piece of infrastructure.
- Redis Streams, for lighter-weight pub/sub with consumer groups, when you don't need Kafka's durability guarantees.
- A managed queue (SQS, Cloud Tasks) when the actual requirement is "don't lose this job," not "replay this log from any point in history."
Pick based on the guarantee you actually need, not the one that sounds most impressive in a system design interview.
The tell that you've over-provisioned
If your event consumers never rewind to an old offset, never have more than one consumer group per topic, and you've never needed to replay a day of events to rebuild a downstream cache — you likely didn't need Kafka's specific guarantees, you needed reliable async delivery. Those are different problems with very different operational costs, and it's worth being honest with yourself about which one you're actually solving before the infrastructure decision gets made for you by inertia.