Messaging Foundations: SQS, SNS & Fan-Out Patterns
SNS and SQS solve different problems and fail differently — SNS is a notification fan-out bus that drops messages after delivery attempts; SQS is a durable work queue that holds messages until a consumer explicitly deletes them. This article covers the at-least-once delivery contract, visibility timeout mechanics, DLQ configuration, SNS-to-SQS fan-out, message filtering policies, and FIFO ordering guarantees.
AWS Serverless Engineering: Lambda to Production
Messaging Foundations: SQS, SNS & Fan-Out Patterns
Every AWS primitive is a tradeoff surface, not a feature toggle. The most common messaging architecture mistake in serverless systems is treating SNS as a durable work queue because "it triggers Lambda." SNS does trigger Lambda — but when Lambda fails and exhausts its retry budget, SNS drops the message. Silently. With no visibility and no recovery path unless you configured an SNS DLQ (which almost no one does, because the Lambda trigger makes it feel handled). SQS, by contrast, holds the message until the consumer explicitly deletes it, and a DLQ captures everything that exhausts maxReceiveCount. These two services solve different problems. Using the wrong one loses work in production.
1. SQS — The Durable Work Queue
SQS guarantees message retention until explicit deletion. A message placed in an SQS queue survives Lambda failures, network partitions, and consumer restarts — it remains in the queue, becoming visible again after the visibility timeout expires.
1.1 The Visibility Timeout Contract
The visibility timeout must be at least 6× your Lambda function timeout. The SQS ESM poller uses a 3-minute session timeout internally. If your Lambda timeout is 60 seconds and the visibility timeout is 30 seconds, messages become visible again before Lambda finishes processing them — producing duplicate deliveries to other Lambda instances while the first is still running.
1.2 Dynamic Visibility Timeout Extension
For long-running processing where you cannot predict duration:
1.3 SQS Standard vs FIFO
| Attribute | Standard | FIFO |
|---|---|---|
| Ordering | Best-effort | Strictly ordered within a Message Group ID |
| Delivery | At-least-once | Exactly-once (within deduplication window) |
| Deduplication | None | Content-based or explicit deduplication ID (5-minute window) |
| Throughput | Unlimited | 300 TPS (3,000 with batching) per queue |
| Price | Lower | Higher |
FIFO Message Group IDs create independent parallel ordered streams. USER#u42 and USER#u99 process concurrently. Within USER#u42, messages are processed in strict send order. Set MessageGroupId to the finest granularity that requires ordering — not a global value (which serializes all traffic) and not a per-message value (which defeats ordering).
2. SNS — The Notification Fan-Out Bus
SNS is a push-based, fan-out notification service. When a message is published to an SNS topic, SNS attempts to deliver it to all subscribers simultaneously. The key word is "attempts" — SNS has a delivery retry policy, and after exhausting retries, it drops the message (unless an SNS DLQ is explicitly configured on the subscription).
2.1 Delivery Semantics
2.2 SNS → SQS Fan-Out Pattern
SNS message filtering policies are evaluated server-side before delivery — the fulfillment queue only receives messages where eventType matches ORDER_CONFIRMED or ORDER_PAID. Without filters, SNS pushes every message to every subscriber, and the subscriber's Lambda must filter in code — paying invocation cost for messages it immediately discards.

3. Long Polling — The Cost-Reduction Default
SQS supports two polling modes. Short polling is the historical default and is actively wasteful:
Lambda ESM uses long polling internally by default — this benefit is automatic for Lambda-triggered queues. For custom consumers (ECS, EC2), explicitly set WaitTimeSeconds=20.
4. DLQ Strategy — What to Monitor and How to Recover
A DLQ is not a passive archive — it is an active operational signal. A non-empty DLQ means work has failed and will not self-heal.

Summary
| Concept | Rule |
|---|---|
| SNS delivery guarantee | Push with retry — drops after retry exhaustion unless DLQ explicitly configured |
| SQS delivery guarantee | Holds until explicit delete — at-least-once with visibility timeout as the delivery contract |
| Visibility timeout | Must be ≥ 6× Lambda timeout; extend dynamically with ChangeMessageVisibility for variable-duration work |
| SNS → SQS fan-out | SNS delivers to SQS → SQS provides durability; best of both services |
| Message filtering | Server-side evaluation — filtered messages never push to subscriber, eliminating unnecessary invocations |
| FIFO Message Group ID | Independent ordered stream per group — different groups process concurrently |
What's Next
In Part 10: EventBridge Architecture — Event Mesh, Pipes & Failure Routing, we move from queue-based messaging to event-mesh routing: how EventBridge's content-based rules replace traffic-cop Lambda functions, how EventBridge Pipes eliminate boilerplate source-to-target wiring, and why every service's DLQ semantics require separate alarms and separate redrive procedures.
This article was developed with AI-assisted deep search, specification cross-referencing, and technical research synthesis.