Event-driven architecture (EDA) is the pattern behind the most scalable systems — from Netflix's microservices to Stripe's payment processing. Instead of services calling each other directly (request-response), they communicate through events (messages about things that happened). This guide covers the patterns, message brokers, and practical implementation of event-driven systems.

Core Event-Driven Patterns

PatternHow It WorksUse CaseComplexity
Event Notification"Order #123 was placed" — fire and forget, subscribers reactSend email on signup, update search index on content changeLow
Event-Carried State TransferEvents contain all data subscribers need (no callback to source)Catalog service publishes full product data — search, pricing, and inventory consume itLow-Medium
Event SourcingState is derived from a sequence of events (not a current snapshot)Banking transactions, audit logs, undo/redo functionalityHigh
CQRS (Command Query Responsibility Segregation)Separate read and write models — writes go through events, reads from materialized viewsHigh-read, complex-query applications (e-commerce product search)High
Saga (Distributed Transaction)A sequence of local transactions, each compensated if a later step failsOrder fulfillment: reserve inventory → charge payment → schedule shippingHigh

Message Broker Comparison

BrokerTypeThroughputLatencyBest For
Apache KafkaDistributed event log1M+ msg/s2-20msHigh-throughput event streaming, event sourcing, data pipelines
RabbitMQMessage queue (AMQP)50K msg/s<1msTask distribution, RPC, complex routing patterns
Amazon SQSManaged message queueUnlimited (AWS scaling)1-50msAWS-native, zero ops, FIFO when ordering matters
Google Pub/SubManaged pub/subUnlimited (GCP scaling)1-10msGCP-native, push subscriptions, global by default
Redis StreamsIn-memory event log100K msg/s<1msLightweight event streaming, already have Redis
NATSLightweight pub/sub1M+ msg/s<1msLow-latency, edge, IoT, microservices

When to Go Event-Driven

SituationEvent-Driven?Why
Monolith → microservices migrationYes — use events to decoupleEvents let services evolve independently
Multiple services need to react to the same eventYes — pub/sub is the patternOne event, many consumers, no coupling
Simple CRUD app, single databaseNo — request-response is fineEDA adds complexity; don't need it yet
Need audit trail of all state changesYes — event sourcingEvents ARE the audit trail
Data analytics / real-time dashboardsYes — event streamingKafka → stream processing → real-time views
Two services need a synchronous responseNo — use REST/gRPCEvents are async; request-response is simpler for sync needs

Implementing a Saga: Order Fulfillment Example

# Saga pattern: orchestration-based (orchestrator coordinates the steps)
# Each step is a local transaction; each has a compensating action

# Step 1: Create order (reserve inventory)
POST /orders {status: PENDING, items: [...]}
  → Event: "OrderCreated" {order_id: 123}
  → Inventory Service reserves stock

# Step 2: Process payment
  → Event: "InventoryReserved" {order_id: 123}
  → Payment Service charges customer
  → Success: "PaymentProcessed" {order_id: 123}
  → Failure: "PaymentFailed" {order_id: 123}
    → Compensate: Inventory Service releases stock

# Step 3: Schedule shipping
  → Event: "PaymentProcessed" {order_id: 123}
  → Shipping Service creates label
  → Success: "OrderFulfilled" {order_id: 123}
  → Failure: "ShippingFailed" {order_id: 123}
    → Compensate: Payment Service refunds
    → Compensate: Inventory Service releases stock

# Key: each compensating action must be idempotent
# (refunding twice = bad; but idempotent refund = safe to retry)

Bottom line: Start with simple event notification (one service emits, others react) before adopting event sourcing or CQRS. For most projects, RabbitMQ or Redis Streams provide enough throughput with simpler operations. Only reach for Kafka when you need replay, long-term retention, or 1M+ msg/s throughput. The biggest mistake is going fully event-driven when simple request-response would suffice — EDA is a powerful tool, not a default architecture. See also: Microservices vs Monolith and Webhook Implementation Guide.