Event-driven architecture (EDA) on AWS lets services communicate through events rather than direct calls, decoupling producers from consumers and improving resilience at scale. In 2026, the combination of Amazon EventBridge, Amazon SQS, and Amazon SNS remains the most widely adopted pattern for building loosely coupled, serverless systems on AWS. This article covers how to wire these services together, when to choose choreography over orchestration, how to handle failures with dead-letter queues, and how to write idempotent consumers that survive duplicate delivery.
Whether you are migrating a monolith or designing a greenfield microservices platform, understanding the trade-offs between these messaging primitives will save you from expensive re-architectures later. By the end, you will know which service to reach for in each situation, how to configure them correctly, and what pitfalls to avoid in production.
What Is Event-Driven Architecture and Why Does It Matter?
Event-driven architecture is a design style where components emit events when something meaningful happens, and other components react to those events asynchronously — without the emitter knowing who (if anyone) is listening. This decoupling is the core value proposition: producers and consumers evolve independently, scale independently, and fail independently.
On AWS, three services form the backbone of most EDA implementations:
- Amazon EventBridge — a serverless event bus that routes events using content-based rules. It supports AWS service events, custom application events, and third-party SaaS events via partner event buses.
- Amazon SQS — a fully managed message queue that buffers messages between producers and consumers, with at-least-once delivery and configurable visibility timeouts.
- Amazon SNS — a pub/sub fanout service that pushes messages to multiple subscribers simultaneously (SQS queues, Lambda functions, HTTP endpoints, email, SMS).
These three services are complementary, not competing. A typical pattern routes an EventBridge event to an SNS topic, which fans out to multiple SQS queues, each consumed by a different Lambda function or ECS task.
Producers and Consumers: Roles and Responsibilities
Producers emit events; consumers react to them — and neither should know about the other. This separation is what makes event-driven systems horizontally scalable and independently deployable.
A producer publishes an event to a bus or topic. In EventBridge, this is a PutEvents API call with a JSON payload up to 256 KB. The event includes a source, detail-type, and detail field. Producers should treat events as immutable facts: "Order placed," not "Please process this order."
A consumer subscribes to events that match a rule or filter. In SQS, a consumer polls the queue (long polling on port 443 over HTTPS) and processes messages within the visibility timeout window (default 30 seconds, configurable up to 12 hours). If processing succeeds, the consumer deletes the message. If it fails or times out, the message becomes visible again for retry.
Key design rules for producers and consumers:
- Producers should include a unique event ID (UUID v4 is standard) in every event payload.
- Consumers must be idempotent — processing the same event twice should produce the same result as processing it once.
- Schema evolution should be additive. Adding new fields is safe; removing or renaming fields is a breaking change.
Choreography vs. Orchestration: Choosing the Right Pattern
Choreography and orchestration are two fundamentally different ways to coordinate distributed workflows, and the wrong choice creates either tight coupling or operational blind spots. EventBridge naturally supports choreography; AWS Step Functions is the primary orchestration tool.
| Dimension | Choreography (EventBridge) | Orchestration (Step Functions) |
|---|---|---|
| Control flow | Distributed across services | Centralized in a state machine |
| Coupling | Low — services react to events | Medium — orchestrator knows all steps |
| Visibility | Harder — requires tracing | Built-in execution history |
| Error handling | Each service handles its own | Centralized retry and catch logic |
| Best for | Independent, parallel reactions | Sequential, stateful workflows |
| Failure isolation | High | Medium |
When to use choreography: A new order triggers an inventory check, a payment charge, and a notification email — all in parallel, all independently. EventBridge routes the order.placed event to three separate SQS queues. Each consumer does its job without knowing the others exist.
When to use orchestration: A loan approval workflow requires step A to complete before step B, with compensating transactions on failure. Step Functions gives you a visual execution graph, built-in retries, and a clear audit trail.
In practice, most production systems use both: choreography for broad event fanout and orchestration for complex, stateful sub-workflows triggered by those events.
Dead-Letter Queues: Your Safety Net for Failed Messages
A dead-letter queue (DLQ) captures messages that could not be processed after a configurable number of attempts, preventing data loss and enabling post-mortem analysis. Every production SQS queue should have a DLQ configured.
Configure a DLQ by setting the redrive policy on your source queue:
{
"deadLetterTargetArn": "arn:aws:sqs:us-east-1:123456789012:my-queue-dlq",
"maxReceiveCount": 3
}
maxReceiveCount is the number of times a message can be received before it is moved to the DLQ. A value of 3–5 is a reasonable starting point for most workloads — low enough to catch persistent failures quickly, high enough to survive transient errors.
EventBridge also has its own DLQ mechanism. When a target (such as an SQS queue or Lambda function) is unavailable, EventBridge retries delivery for up to 24 hours using exponential backoff. If all retries are exhausted, the event is sent to a target-level DLQ (an SQS queue you specify on the EventBridge rule target).
Operational practices for DLQs:
- Set a CloudWatch alarm on
ApproximateNumberOfMessagesVisiblefor your DLQ. Any message in a DLQ is a signal that needs investigation. - Build a redrive process — a Lambda or Step Functions workflow that replays DLQ messages back to the source queue after you fix the underlying bug.
- Store DLQ messages with enough context (original event ID, timestamp, error reason) to diagnose failures without re-running the entire pipeline.
Idempotency: Building Consumers That Survive Duplicate Delivery
SQS guarantees at-least-once delivery, which means your consumer will occasionally receive the same message more than once — idempotency is not optional, it is a correctness requirement. Standard SQS queues can deliver duplicates; even SQS FIFO queues (which offer exactly-once processing within a 5-minute deduplication window) can deliver duplicates outside that window.
The standard pattern for idempotent consumers:
- Extract the idempotency key from the message — typically the event ID embedded by the producer.
- Check a persistent store (DynamoDB, ElastiCache, or RDS) to see if this key has already been processed.
- If already processed, acknowledge the message (delete it from SQS) and return without side effects.
- If not processed, execute the business logic, then write the key to the store with a TTL (e.g., 24–48 hours).
AWS Lambda Powertools (available for Python, TypeScript, Java, and .NET) provides a production-ready idempotency utility backed by DynamoDB. It handles the check-and-set atomically using a conditional write, preventing race conditions when the same message arrives on two Lambda instances simultaneously.
For DynamoDB-backed idempotency, the table needs only two attributes: id (the idempotency key, partition key) and expiration (a TTL attribute). The cost is minimal — a single conditional PutItem per message.
SQS vs. SNS vs. EventBridge: Picking the Right Tool
Choosing between these services is one of the most common architecture questions on AWS. The answer depends on your routing needs, delivery guarantees, and consumer topology.
| Feature | SQS | SNS | EventBridge |
|---|---|---|---|
| Delivery model | Pull (polling) | Push (fan-out) | Push (rule-based routing) |
| Max message size | 256 KB | 256 KB | 256 KB |
| Retention | Up to 14 days | No retention | No retention (archive optional) |
| Content-based routing | No | No (attribute filtering) | Yes (rich JSON pattern matching) |
| Cross-account delivery | Yes (queue policy) | Yes | Yes (event bus policy) |
| FIFO / ordering | Yes (FIFO queues) | Yes (FIFO topics) | No |
| SaaS integrations | No | No | Yes (50+ partners) |
| DLQ support | Native | Yes (for SQS subscribers) | Yes (target-level) |
Use SQS when you need buffering, backpressure, and reliable pull-based consumption. Use SNS when you need to fan out a single message to multiple heterogeneous subscribers instantly. Use EventBridge when you need content-based routing, schema registry, cross-account event sharing, or SaaS integrations.
The most resilient pattern combines all three: EventBridge routes and filters → SNS fans out → SQS buffers → Lambda or ECS consumes.
Key Takeaways
- Event-driven architecture decouples producers from consumers, enabling independent scaling and deployment — EventBridge, SQS, and SNS are the core AWS primitives.
- Choreography (EventBridge-driven) is best for parallel, independent reactions; orchestration (Step Functions) is best for sequential, stateful workflows — most systems need both.
- Dead-letter queues are mandatory in production; configure CloudWatch alarms on DLQ depth and build a redrive process before you go live.
- Idempotency is a correctness requirement, not an optimization — use a persistent idempotency key store (DynamoDB + TTL) and consider AWS Lambda Powertools to avoid reinventing the wheel.
- SQS FIFO queues provide exactly-once processing within a 5-minute deduplication window but have a throughput limit of 3,000 messages/second with batching (vs. nearly unlimited for standard queues).
- EventBridge event archives let you replay historical events — invaluable for debugging, backfilling new consumers, and disaster recovery.
- Schema Registry in EventBridge (available since 2023) auto-discovers event schemas and generates typed code bindings, reducing integration errors between teams.
Frequently Asked Questions
What is the difference between EventBridge and SNS?
EventBridge routes events using rich JSON pattern matching on any field in the event payload, supports SaaS partner integrations, and includes a schema registry. SNS is a simpler push-based fanout service that delivers a message to all subscribers simultaneously with basic attribute-based filtering. Use EventBridge when you need content-based routing or cross-account event sharing; use SNS when you need fast, simple fanout to many subscribers.
When should I use SQS FIFO instead of a standard queue?
Use SQS FIFO when message ordering within a group matters — for example, processing bank transactions for a single account in sequence. FIFO queues guarantee order and exactly-once processing within a 5-minute deduplication window, but they cap throughput at 3,000 messages/second with batching. Standard queues offer higher throughput and lower cost but deliver messages out of order and may deliver duplicates.
How do I prevent a poison-pill message from blocking my SQS queue?
Set a maxReceiveCount in the redrive policy (typically 3–5) so that a message that repeatedly fails processing is moved to the DLQ automatically. Also set an appropriate visibility timeout — it should be longer than your maximum processing time to prevent premature re-delivery. Monitor DLQ depth with CloudWatch and alert on any non-zero value.
Can EventBridge deliver events to SQS directly without SNS in the middle?
Yes. EventBridge supports SQS queues as direct rule targets. You only need SNS in the middle when you need to fan out a single EventBridge event to multiple SQS queues simultaneously, or when you need to deliver to non-SQS subscribers (HTTP endpoints, email) at the same time.
How do I handle schema evolution without breaking consumers?
Follow additive-only changes: add new optional fields, never remove or rename existing ones. Use the EventBridge Schema Registry to version schemas and generate typed bindings. Consumers should use tolerant reader patterns — ignore unknown fields rather than failing on them. For breaking changes, version your detail-type (e.g., order.placed.v2) and run old and new consumers in parallel during the migration window.
What is the maximum throughput of EventBridge?
EventBridge supports up to 10,000 events per second per account per region by default (as of 2026), with soft limits that can be raised via a service quota request. For very high-throughput workloads (millions of events per second), consider using Kinesis Data Streams as the ingestion layer and EventBridge Pipes to connect it to downstream targets.
Is event-driven architecture always the right choice?
No. EDA adds operational complexity — distributed tracing, DLQ management, idempotency logic, and eventual consistency are all harder to reason about than a synchronous request/response call. For simple CRUD APIs, low-traffic internal tools, or workflows where the caller needs an immediate response, a synchronous REST or gRPC call is often simpler and more appropriate. Adopt EDA where the benefits of decoupling and independent scaling outweigh the added complexity.
Draw this in seconds with draft1. Describe your architecture in plain English and draft1 generates an editable AWS/cloud diagram plus documentation — no dragging boxes around. Try it free.