Event-driven architecture (EDA) sounds enterprise-y. Kafka clusters. Schema registries. Teams of platform engineers. But the core concepts? They’re surprisingly accessible—and incredibly useful—even for small teams.
Why Events Matter (Even for Small Projects)
The alternative to events is tight coupling. Service A calls Service B directly. Service B calls Service C. Soon you have a distributed monolith where everything needs to know about everything else.
Events flip this model. Instead of “Service A tells Service B to do something,” it becomes “Service A announces what happened, and anyone who cares can respond.”
This shift enables:
- Independent deployments — Services don’t need synchronized releases
- Failure isolation — One service crashing doesn’t cascade
- Flexible scaling — Heavy consumers can scale independently
- Natural audit trails — Events are facts about what happened
Start with What You Have
You don’t need dedicated message infrastructure on day one.
Level 0: Database as Queue
Your database can be a perfectly fine event store:
| |
Publishers insert rows. Consumers poll and mark processed:
| |
Pros: Zero new infrastructure. ACID guarantees. Works with your existing backup strategy.
Cons: Polling overhead. Single database as bottleneck. Not great for high throughput.
Level 1: Redis Streams
When you outgrow database polling, Redis Streams offer a nice middle ground:
| |
Pros: Consumer groups for parallel processing. Automatic acknowledgment. Built-in backpressure.
Cons: Persistence requires configuration. No built-in dead letter queues.
Level 2: Managed Queues
When you need durability guarantees without operational overhead:
- AWS SQS + SNS — Pub/sub with queue subscribers
- Google Cloud Pub/Sub — Similar model
- Azure Service Bus — Enterprise features
These are “boring” in the best way—reliable, scalable, managed.
Event Design That Doesn’t Suck
Events Are Facts, Not Commands
Bad event:
| |
Good event:
| |
The first is a command—it tells someone what to do. The second is a fact—it announces what happened. The difference matters because:
- Facts can have multiple consumers (email service, analytics, CRM sync)
- Facts are replayable (you can rebuild state from events)
- Facts don’t create temporal coupling (consumer doesn’t need to exist at publish time)
Include Enough Context
Events should be self-contained enough that consumers don’t need to call back to the publisher:
| |
Yes, this duplicates data. That’s okay. Network calls are expensive; storage is cheap.
Version From Day One
| |
When you need to add fields, bump the version. Consumers can handle multiple versions during migration.
Patterns That Pay Off
The Outbox Pattern
Problem: You update your database and publish an event, but what if the publish fails after the database commit?
Solution: Write the event to an “outbox” table in the same transaction, then publish from there:
| |
Dead Letter Queues
Events that fail processing shouldn’t disappear:
| |
Check your DLQ regularly. Those failures are bugs or edge cases waiting to be understood.
Idempotent Consumers
Events can be delivered more than once. Your consumers must handle this:
| |
When to Graduate to “Real” Infrastructure
Consider dedicated message brokers (Kafka, RabbitMQ, etc.) when:
- Throughput exceeds thousands of events per second
- Ordering guarantees matter across partitions
- Replay capability is a core requirement
- Multiple teams need independent consumption
Until then? Redis Streams or managed queues will take you surprisingly far.
The Mindset Shift
Event-driven architecture isn’t about the tools. It’s about asking different questions:
- Instead of “who needs this data?” → “what happened that others might care about?”
- Instead of “how do I update everything?” → “how do I announce this change?”
- Instead of “what if that service is down?” → “how do I ensure this event persists?”
Start small. One event type. One consumer. Feel the decoupling. Then expand.
The best part? You can adopt this incrementally. Keep your existing REST APIs. Add events alongside them. Migrate piece by piece as the pattern proves its value.
That’s architecture that respects both your current constraints and your future ambitions.