Amazon SNS, Past the Basics
A practical, intermediate-depth walkthrough of how Amazon SNS actually fans out messages, filters them before delivery, retries failed subscribers, and where teams get it wrong in production.
You already know SNS is a pub/sub service — a publisher sends one message, a topic fans it out to many subscribers. That’s the elevator pitch, and it’s basic-tier knowledge. What actually determines whether an SNS-based architecture holds up under real traffic is a narrower set of mechanics: how filter policies decide which subscribers even see a message, what “at-least-once delivery” really obligates your subscribers to handle, how retry backoff and dead-letter queues interact, and where FIFO topics trade throughput for strict ordering. This article stays in that intermediate zone throughout — no “what is pub/sub” primer — and goes straight to the mechanics, trade-offs, and failure modes that show up once SNS is carrying production traffic.
ACore Concepts You Actually Need at This Level
Skipping “what is a topic” means we go straight to the mechanisms that decide whether messages actually reach the right subscribers, in the right shape, reliably.
Topics, Subscriptions, and Protocols
A topic is a named channel publishers send to; a subscription binds one endpoint — an SQS queue, a Lambda function, an HTTPS endpoint, an email address, an SMS number, a mobile push endpoint, or a Kinesis Data Firehose delivery stream — to that topic. The intermediate-level detail worth internalizing is that each protocol has meaningfully different delivery guarantees and failure behavior: SQS and Lambda subscriptions get automatic retry with backoff and can be paired with a dead-letter queue, while HTTP/S subscriptions retry on a fixed policy you configure, and email/SMS have no retry concept at all in the same sense — a bounced email is simply gone.
Message Attributes and Filter Policies
Message attributes are structured key-value metadata attached to a published message, separate from the message body. A filter policy attached to a subscription evaluates those attributes and decides whether that specific subscriber receives the message at all — evaluated by SNS itself, before delivery, so a subscriber never even sees a message that doesn’t match its filter. This is what turns a single topic into something closer to a routable event bus rather than a blunt broadcast-to-everyone mechanism.
Standard vs. FIFO Topics
Standard topics offer nearly unlimited throughput but only best-effort ordering and at-least-once delivery, meaning duplicates are possible. FIFO topics guarantee strict ordering and exactly-once delivery within a message group, but only when paired with FIFO subscribers (FIFO SQS queues) and at meaningfully lower throughput ceilings. Choosing between them is an architectural decision made per use case, not a default — ordering and dedup do not come free.
The Fanout Pattern, Precisely
“Fanout” specifically means one published message is delivered to multiple independent subscribers, each processing it for a different purpose — an order-placed event might fan out to an inventory service, a billing service, and an analytics pipeline simultaneously, each via its own SQS queue subscribed to the same topic. This decouples the publisher from ever needing to know how many consumers exist or what they each do with the message.
Think of a topic as a radio station, subscribers as receivers tuned to it, and a filter policy as each receiver’s own squelch setting — the station broadcasts everything, but each receiver only lets through the signal that matches what it cares about. A FIFO topic is the same station broadcasting strictly in the order songs were recorded, with no two receivers ever hearing the same song twice.
Most production fanout architectures subscribe SQS queues to the topic rather than subscribing Lambda or HTTP endpoints directly, specifically to get a durable buffer and independent retry/backoff per consumer — a slow or failing consumer then can’t affect the others or the publisher.
Message Deduplication in FIFO Topics
FIFO topics prevent duplicate publishes using either a deduplication ID you supply explicitly, or content-based deduplication (a SHA-256 hash of the message body) within a five-minute deduplication interval. This matters because “exactly-once” is scoped narrowly — it protects against the publisher retrying the same publish call, not against a subscriber processing a successfully delivered message twice due to its own retry logic.
Message Attributes vs. Message Body
A common intermediate mistake is conflating what belongs in message attributes versus the message body. Attributes are meant for routing metadata that filter policies evaluate — an event type, a tenant ID, a priority level — kept small and structured. The body carries the actual payload a subscriber needs to do its work. Stuffing routing-relevant fields only inside the body (without also surfacing them as attributes) forces every subscriber to parse and inspect the full payload just to decide whether a message is even relevant to them, defeating the purpose of platform-level filtering.
Message Ordering Outside of FIFO
Standard topics make no ordering guarantee whatsoever — messages can arrive at a subscriber in a different order than they were published, especially under retry conditions. Teams that assume “usually arrives in order” is good enough for a standard topic are making an implicit ordering assumption the service was never designed to uphold; if order matters even occasionally, that’s a signal to use a FIFO topic rather than hoping standard-topic behavior stays consistent.
Subscription Filter Scope: MessageBody vs. MessageAttributes
Filter policies traditionally evaluated only message attributes, but SNS also supports body-based filtering for JSON message bodies, letting a filter policy reference fields nested directly inside the payload rather than requiring the publisher to duplicate that information as a separate attribute. This is a meaningful intermediate-level choice: attribute-based filtering keeps routing metadata explicit and separate from payload structure, while body-based filtering avoids duplication when the payload already contains everything needed to route it — each has a place depending on how tightly coupled you want your routing logic to be to the payload’s internal shape.
Opt-Out and Compliance Considerations for SMS/Email
SMS and email subscriptions carry their own compliance obligations that don’t apply to SQS, Lambda, or HTTPS subscriptions — SMS delivery is subject to carrier filtering and per-country regulations, and recipients must be able to opt out. These constraints exist entirely outside SNS’s control plane, which is another reason SMS and email are generally reserved for genuinely human-facing notifications rather than treated as just another protocol option for system-to-system fanout.
BArchitecture & Components
SNS is a managed pub/sub layer, but its behavior is shaped heavily by which subscriber protocols you attach and how access policies gate publish and subscribe actions.
graph TB
P[Publisher: App/Service/EventBridge]
P -->|Publish| T[SNS Topic]
T --> FP{Filter Policy per Subscription}
FP -->|Match| S1[SQS Queue - Order Service]
FP -->|Match| S2[Lambda Function - Notifications]
FP -->|Match| S3[HTTPS Endpoint - Partner Webhook]
FP -->|Match| S4[Email Subscription]
FP -->|No Match| DROP[Message Not Delivered to This Subscriber]
S1 --> DLQ1[Dead-Letter Queue]
S2 --> DLQ2[Dead-Letter Queue]
Fig. B1 — One publish, filtered per-subscriber fanout across heterogeneous protocols
The Core Component Inventory
Topic
The named pub/sub channel; standard or FIFO, with its own access policy and delivery-status logging config.
Subscription
Connects one endpoint/protocol to a topic, with its own filter policy and redrive (DLQ) configuration.
Topic Policy
A resource-based IAM policy controlling which principals can publish, subscribe, or manage the topic.
Filter Policy
Per-subscription rules evaluated against message attributes (or the message body, with body-based filtering) before delivery.
Dead-Letter Queue
An SQS queue that captures messages a subscription failed to deliver after exhausting retries.
SSE-KMS
Optional server-side encryption of the topic using a customer-managed or AWS-managed KMS key.
Protocol Choice Is an Architectural Decision
Subscribing SQS gives you a durable, poll-based buffer with consumer-controlled processing rate. Subscribing Lambda gives you immediate, push-based invocation with automatic scaling but tighter coupling to Lambda’s own concurrency and timeout limits. Subscribing HTTPS gives you the most flexibility (any endpoint, anywhere) but the weakest guarantees — you own the retry-worthy status codes and the endpoint’s availability entirely. Choosing the wrong protocol for a given consumer’s reliability needs is one of the most common intermediate-level architecture mistakes.
Production Example — Netflix
Netflix has publicly discussed using SNS-style pub/sub fanout patterns to decouple event producers from the many independent internal services that need to react to the same event — new content availability, playback events — without producers needing any knowledge of which downstream teams are listening.
Standard vs. FIFO Topic Architecture, in Practice
A standard topic’s internal architecture is optimized for maximum publish throughput and broad fanout — it accepts near-unlimited concurrent publishes and distributes them to subscribers independently, which is exactly why it can’t also guarantee strict ordering across all of that concurrency. A FIFO topic constrains itself specifically to preserve ordering within each message group, which necessarily means serializing processing within that group — the architecture trade-off is not an accident of implementation, it’s the direct consequence of what each topic type promises to guarantee.
Access Policy Structure
A topic’s access policy is a standard IAM resource policy document with statements scoped to specific actions (sns:Publish, sns:Subscribe, sns:SetTopicAttributes) and specific principals, optionally narrowed further with condition keys like source ARN or source account. The default policy created alongside a new topic is permissive within the owning account but explicitly denies cross-account access until a statement is added — a deliberate secure-by-default posture that surprises teams expecting an open topic.
Choosing Between Direct Service Integration and a Custom Publisher
Many AWS services can publish to an SNS topic natively as part of their own event model — S3 object events, CloudWatch Alarm state changes, Auto Scaling lifecycle events — without any custom application code. The intermediate-level judgment call is recognizing when to lean on that native integration versus writing a custom publisher: native integrations are simpler and require no code to maintain, but they publish exactly the event shape and timing the source service defines, with no room to enrich or reshape the message before it hits the topic. A custom publisher trades that simplicity for full control over payload shape, timing, and the ability to add business-specific attributes for filtering.
CInternal Working
Understanding what SNS actually guarantees — and what it explicitly does not — explains almost every “why did I get a duplicate” or “why didn’t this arrive” question.
At-Least-Once Delivery, Not Exactly-Once (for Standard Topics)
Standard SNS topics guarantee a message will be delivered at least once to each matching subscriber, but not exactly once — network retries, internal redundancy, and subscriber-side timeouts can all cause the same message to arrive twice. This is a design constraint, not a bug: every subscriber consuming a standard topic must be written to handle duplicate messages safely, typically via an idempotency key or idempotent database writes.
How Filter Evaluation Actually Happens
When a message is published, SNS evaluates each subscription’s filter policy against the message’s attributes (or, with body-based filtering enabled, against fields inside the JSON body itself) independently and in parallel — a message can match zero, some, or all subscriptions on a topic. Filtering happens inside SNS itself, which means non-matching subscribers incur no cost and no invocation at all; this is meaningfully different from filtering downstream in each consumer, which would waste compute on messages that get immediately discarded.
Retry Policy and Backoff, Per Subscription
Each HTTP/S subscription can have its own retry policy: number of retries, backoff function (linear, arithmetic, geometric, or exponential), and minimum/maximum delay. SQS and Lambda subscriptions use SNS’s built-in retry behavior with exponential backoff automatically. The critical intermediate detail is that these retries are scoped per subscription — a slow or failing HTTPS subscriber retrying repeatedly has zero effect on delivery to the other subscribers of the same topic.
| Protocol | Retry Behavior | DLQ Support |
|---|---|---|
| SQS | Automatic, exponential backoff | Yes |
| Lambda | Automatic, exponential backoff | Yes |
| HTTP/S | Configurable per-subscription policy | Yes |
| Email/SMS | No meaningful retry (best-effort send) | No |
A subscriber that returns a success status code but then fails to actually process the message (an application-level bug, not a delivery failure) will never trigger SNS’s retry or DLQ mechanism — SNS only knows about delivery success or failure at the transport level, not whether your code did the right thing with the payload.
How Lambda Subscriptions Differ from SQS Subscriptions Internally
When Lambda is subscribed directly to an SNS topic, SNS invokes the function synchronously per message (technically, Lambda’s own asynchronous invocation model handles the actual execution, but from SNS’s perspective delivery is push-based and immediate). This means a burst of published messages can trigger a corresponding burst of concurrent Lambda invocations, bounded by the function’s own concurrency limits — very different from an SQS-subscribed consumer, which pulls messages at whatever rate its own polling logic chooses. This distinction is exactly why high-burst workloads are often routed through an SQS subscription rather than directly to Lambda: the queue absorbs the burst and lets the consumer control its own processing rate.
Confirming Subscriptions Programmatically
While the console and SDK flows often auto-confirm SQS and Lambda subscriptions (since SNS can verify ownership through IAM permissions rather than a manual click), HTTP/S endpoints must actively call back with the confirmation token SNS sends in its initial SubscriptionConfirmation request. An endpoint that doesn’t implement this confirmation handshake will never receive real notifications regardless of how correctly everything else is configured.
Why Retries Alone Don’t Guarantee Delivery
Retry policies bound how hard SNS tries, not whether it ultimately succeeds — a subscriber endpoint that’s been offline for an extended outage will still exhaust its retry budget and fall back to the DLQ (or be dropped, without one) regardless of how generous the backoff configuration is. Treating “we have retries configured” as equivalent to “delivery is guaranteed” is a subtle but consequential misunderstanding; retries buy resilience against transient failures, not against sustained outages.
DData Flow & Lifecycle
Tracing one message end to end, from publish call to final consumer processing, clarifies exactly where each guarantee and failure mode lives.
sequenceDiagram
participant Pub as Publisher
participant Topic as SNS Topic
participant Filter as Filter Policy Engine
participant Sub as Subscriber (SQS/Lambda/HTTPS)
participant DLQ as Dead-Letter Queue
Pub->>Topic: Publish(message, attributes)
Topic->>Filter: Evaluate against each subscription
alt Attributes match
Filter->>Sub: Deliver message
alt Delivery succeeds
Sub-->>Topic: Ack / 200 OK
else Delivery fails after retries
Filter->>DLQ: Move message to DLQ
end
else No match
Filter--xSub: Not delivered
end
Fig. D1 — Full message lifecycle including filter short-circuit and DLQ redrive
Lifecycle of a Topic Itself
Create Topic
Choose standard or FIFO; this choice cannot be changed later without creating a new topic.
Attach Access Policy
Define which principals may publish and which may subscribe.
Add Subscriptions
Each with its own protocol, filter policy, and optional DLQ redrive configuration.
Confirm Subscriptions
HTTP/S, email, and SMS subscriptions require explicit confirmation before they start receiving messages.
Publish & Monitor
Ongoing publish traffic monitored via CloudWatch delivery-status metrics and logs.
Subscription confirmation is like a mailing list requiring you to click “yes, subscribe me” in a confirmation email before any newsletters actually arrive — SNS won’t deliver to an HTTP endpoint, email address, or SMS number until that endpoint proves it’s really listening, which prevents accidental or malicious blasting of unconfirmed addresses.
Raw Message Delivery
By default, SNS wraps the published payload in an SNS-specific JSON envelope (including metadata like MessageId and Timestamp) before delivering it to SQS or HTTP/S subscribers. Enabling raw message delivery strips that envelope so the subscriber receives exactly the published payload — necessary when a downstream consumer expects a specific message format and shouldn’t need to unwrap an SNS envelope first.
Message Retention Absence and Its Downstream Effects
Because SNS itself retains nothing once a message has been handed off (successfully or to a DLQ), the entire notion of “replaying history” only exists at whatever durable subscriber you’ve attached — an SQS queue retains messages up to its configured retention period, but a Lambda or HTTP/S subscriber that briefly went offline simply misses whatever was published during that window unless a DLQ captured the failed deliveries. Designing for this means deciding, per consumer, whether missing a message during an outage is acceptable or whether that consumer needs a durable buffer in front of it.
EAdvantages, Disadvantages & Trade-offs
Advantages
- True fanout to many heterogeneous subscriber types from a single publish call.
- Filter policies push routing logic into the platform instead of every consumer.
- No infrastructure to provision — scales automatically with publish volume.
- Native DLQ support per subscription isolates failing consumers from the rest.
- FIFO topics available when strict ordering and dedup genuinely matter.
Disadvantages
- At-least-once delivery on standard topics forces every subscriber to handle duplicates.
- 256 KB message size limit requires an offload pattern for larger payloads.
- FIFO topics have materially lower throughput ceilings than standard topics.
- No message replay — once delivered (or expired), a message can’t be re-read by a new subscriber the way a queue or stream allows.
- Email/SMS subscriptions offer no retry guarantee, unsuitable for anything requiring durability.
FPerformance & Scalability
Standard Topics Scale Nearly Transparently
Standard SNS topics scale to very high publish rates without any provisioning from you — the scalability ceiling that actually matters in practice is almost always on the subscriber side (Lambda concurrency limits, SQS consumer throughput, a partner’s HTTPS endpoint capacity), not on SNS itself.
FIFO Throughput Is Bounded by Design
FIFO topics trade throughput for ordering guarantees: throughput is capped per message group, so the practical way to scale a FIFO workload horizontally is to increase the number of distinct message groups (each group processed independently and in order) rather than expecting a single group to absorb arbitrary load. Choosing too few message groups is a common cause of unexpected FIFO throttling.
Large Payloads via the Extended Client Pattern
Because messages are capped at 256 KB, payloads larger than that (a large JSON document, a file reference bundle) are handled by publishing a small pointer message that references the actual payload stored in S3 — commonly implemented with the Amazon SNS/SQS Extended Client Library, which handles the S3 put/get transparently on both the publish and consume side.
Batch related attribute-driven decisions into a small, stable set of attribute keys rather than constantly changing filter policies — frequent filter policy edits on high-subscription-count topics can become an operational burden of their own.
Publish Batching
The PublishBatch API accepts up to ten messages in a single request, reducing the per-message API-call overhead for publishers emitting many related messages in quick succession — useful for bulk operations like re-publishing a backlog of events after fixing a downstream issue, though each message in the batch is still evaluated and delivered independently by every subscription’s filter policy.
Attribute Count and Filter Policy Complexity Limits
A message can carry up to ten attributes, and filter policies support a bounded set of operators (exact match, prefix match, numeric range, anything-but). Designing attribute schemas that stay within these bounds while remaining expressive enough for real routing needs is a genuine design exercise on topics with many heterogeneous subscribers — over-engineering the attribute schema up front, before real subscriber requirements exist, is a common way teams paint themselves into needing a redesign later.
Throughput Planning for Subscriber Fan-Out Ratios
A topic’s effective load on the rest of the system is the publish rate multiplied by the number of matching subscriptions per message, not just the raw publish rate in isolation. A topic publishing a modest 100 messages per second to ten matching subscribers is generating 1,000 downstream deliveries per second — capacity planning for the subscribers (Lambda concurrency, SQS consumer throughput, a partner endpoint’s rate limit) needs to account for this multiplier, not just the publisher’s own traffic.
Cost Shape Worth Planning For
SNS pricing is charged per million publish requests plus a separate per-notification-delivery charge that varies by protocol (SQS and Lambda deliveries are typically the cheapest; SMS carries meaningfully higher per-message cost that also varies by destination country). Because a single publish can generate many deliveries through fanout, the total monthly cost tracks the fanout multiplier described above much more closely than it tracks the raw publish volume — a detail worth including explicitly in any cost projection done before adding a new high-fanout topic to a high-traffic path.
GHigh Availability & Reliability
SNS is multi-AZ and regional by default — the reliability decisions that matter at this level are about DLQ configuration, cross-region delivery, and subscriber-side idempotency.
Multi-AZ by Default, Cross-Region Requires Explicit Design
Within a region, SNS is deployed redundantly across multiple Availability Zones with no configuration required. Cross-region resilience — surviving an entire region being degraded — requires explicitly publishing to topics in more than one region, or fanning a single event out to a cross-region replication mechanism, since SNS itself does not replicate a topic’s messages across regions automatically.
Dead-Letter Queues Are Not Optional in Production
Any subscription without a configured DLQ silently drops messages once retries are exhausted — there’s no default fallback storage. Configuring a DLQ per subscription turns “message disappeared with no trace” into “message is sitting in a queue you can inspect and redrive,” which is the difference between an invisible data-loss bug and a recoverable operational incident.
Anti-pattern
Subscribing a consumer without a DLQ and assuming “SNS retries automatically” is sufficient reliability on its own.
Why It Fails
Retries are finite. Once exhausted, a message with no DLQ configured is gone permanently with no audit trail, which turns a transient downstream outage into permanent data loss.
Better Approach
Attach a DLQ to every subscription that matters, alarm on its depth in CloudWatch, and build a redrive process (manual or automated) for reprocessing once the downstream issue is fixed.
Blast-Radius Isolation Across Subscribers
Because retries and DLQ configuration are scoped per subscription, one consumer’s persistent failure is fully isolated from every other consumer of the same topic by design — a partner’s misconfigured HTTPS endpoint retrying and eventually landing in its own DLQ has zero effect on the internal SQS-subscribed services also reading from that topic. This isolation is one of SNS’s strongest reliability properties and a major reason fanout architectures favor it over point-to-point integrations, where one consumer’s outage more easily cascades back toward the producer.
Handling Partial Fanout Failures
A single publish can succeed at the topic level while failing to reach one or more subscribers — from the publisher’s perspective, the publish call itself only confirms the message was accepted by SNS, not that every subscriber successfully received it. Systems that need end-to-end delivery confirmation across all subscribers must build that tracking themselves, typically by having each critical subscriber emit its own completion signal that a separate process reconciles against the original publish.
Chaos and Failure Injection for Fanout Architectures
Because per-subscription isolation is one of SNS’s core reliability claims, it’s worth validating rather than assuming: deliberately breaking one subscriber (returning errors, or removing its permissions temporarily) in a staging environment and confirming the other subscribers keep receiving messages normally is a low-effort way to catch a misconfiguration — like an overly broad topic-level retry setting that accidentally couples subscribers together — before it surfaces during a real production incident.
Planning for Region-Wide Degradation
Because cross-region resilience is not automatic, teams running SNS-dependent workloads with a genuine multi-region availability requirement need to decide, ahead of any incident, exactly which layer owns replication: publishing to two regional topics from the application layer, mirroring events through a cross-region EventBridge bus, or accepting region-scoped availability and building the recovery runbook around re-publishing from a durable source of truth once the primary region recovers. Deciding this during an actual regional event, rather than in advance, is consistently the more expensive path.
HSecurity
Topic Policies Are the Primary Access Boundary
A topic policy (a resource-based IAM policy attached directly to the topic) controls which AWS principals can publish, subscribe, or manage the topic — this is enforced independently of any IAM identity-based policy the caller’s own role might have, and both must allow the action for it to succeed.
SSE-KMS Encryption
Encrypts message content at rest using a customer-managed or AWS-managed KMS key; adds a small latency and KMS API-call cost per publish.
TLS Enforcement
A topic policy condition can require HTTPS/TLS for all publish and subscribe API calls, rejecting plaintext connections outright.
VPC Endpoints
An interface VPC endpoint lets resources inside a VPC publish to SNS without traversing the public internet.
Resource Policy Grants
The topic policy, not IAM alone, is what allows a different AWS account’s principal to publish or subscribe.
Least-Privilege for Subscription Endpoints
An SQS queue or Lambda function subscribed to an SNS topic must itself grant SNS permission to deliver to it — a queue policy for SQS, a resource-based policy for Lambda — which is a separate permission from the topic policy governing who may subscribe in the first place. Auditing SNS security means checking both sides of every subscription, not just the topic.
Data Residency and Message Content Considerations
Because a topic is regional, messages published to it never leave that region unless a subscriber or downstream process explicitly moves them — important for workloads with data residency requirements, since it means the compliance boundary is largely defined by where you create the topic and where its subscribers live, not by anything SNS does implicitly. Teams operating in regulated industries commonly pair this regional scoping with SSE-KMS using a key whose policy itself restricts usage to approved principals, giving two independent layers of access control over sensitive message content.
Auditing Subscription Confirmations
Every subscription confirmation — including ones an attacker might attempt against a topic with an overly permissive Subscribe policy — is logged in CloudTrail. Reviewing unexpected ConfirmSubscription events alongside topic policy changes is a practical way to catch a misconfigured or overly broad access policy before it results in an unintended external party receiving live production events.
| Threat | Primary Mitigation |
|---|---|
| Unauthorized publish | Topic policy restricting the Publish action to specific principals |
| Unauthorized subscribe / eavesdropping | Topic policy restricting Subscribe, plus subscription confirmation |
| Data exposure at rest | SSE-KMS encryption on the topic |
| Data exposure in transit | TLS-only condition in the topic policy |
| Public-internet exposure from within a VPC | Interface VPC endpoint for SNS |
IMonitoring, Logging & Metrics
The CloudWatch Metrics That Matter
- NumberOfMessagesPublished — total successful publishes to the topic.
- NumberOfNotificationsDelivered — successful deliveries across all subscriptions.
- NumberOfNotificationsFailed — deliveries that failed after exhausting retries; the primary signal something downstream is broken.
- PublishSize — distribution of message sizes, useful for spotting payloads approaching the 256 KB limit before they start failing.
- SMSMonthToDateSpentUSD — relevant only for SMS-heavy topics, worth alarming on to catch runaway send volume.
Delivery Status Logging
Enabling delivery status logging on a topic writes per-message, per-subscription success and failure logs to CloudWatch Logs — this is the only way to see delivery outcomes at the individual message level rather than just aggregate counts, and it’s essential when debugging why one specific subscriber intermittently misses messages while others don’t.
CloudTrail for Configuration Auditing
Every topic policy change, subscription creation, and encryption setting change is recorded in CloudTrail, which is the standard way to answer “who changed the access policy that let an unexpected principal publish” during a security review.
Production Example — Zillow
Zillow has publicly described using SNS delivery-status metrics and DLQ depth alarms to detect degraded downstream consumers quickly, treating a rising NumberOfNotificationsFailed count as an early warning signal ahead of customer-visible impact.
JDeployment & Cloud Integration
Infrastructure as Code for Topics and Subscriptions
Mature teams define topics, subscriptions, filter policies, and DLQ redrive configuration through CloudFormation, CDK, or Terraform, since filter policies in particular tend to drift quickly when edited by hand in the console across many subscriptions.
Cross-Region Event Distribution
For architectures spanning multiple regions, a common pattern publishes to a regional SNS topic, then either replicates the event via an application-level cross-region publish, or routes through EventBridge’s cross-region event bus targeting, since SNS itself has no native cross-region topic replication.
EventBridge and SNS Together
SNS and Amazon EventBridge solve overlapping but distinct problems: EventBridge is built for rule-based routing across many event sources and targets with a schema registry, while SNS is a simpler, lower-latency pub/sub primitive well suited to straightforward fanout. A common intermediate-level pattern uses EventBridge as the central router and SNS as one of its many possible targets, specifically to get SNS’s mature fanout-to-heterogeneous-protocols behavior for a subset of routed events.
Observability Tooling Integration
Deployment pipelines for SNS-based architectures commonly wire delivery-status logs and DLQ depth metrics into whatever centralized observability stack the organization already uses (CloudWatch dashboards, a third-party APM tool via a metrics exporter, or a SIEM for security-relevant CloudTrail events) rather than treating SNS monitoring as a standalone concern — since a fanout topic’s health is really a proxy for the health of every subscriber behind it, dashboards that correlate topic-level metrics with each subscriber’s own service-level metrics give a much faster path to root cause during an incident than either view alone.
CI/CD for Filter Policy Changes
Because filter policies determine which subscribers receive which messages, a change deployed without review can silently stop delivering to a consumer that still expects messages — treating filter policy changes with the same pull-request review rigor as application code, rather than as a quick console edit, avoids a class of “messages just stopped arriving” incidents that are hard to trace back to a policy change days later.
Multi-Account Topologies
In organizations using separate AWS accounts per team or environment, a shared “hub” account often owns core event topics, with subscriber accounts granted cross-account subscribe permissions via the topic policy — this centralizes ownership and auditing of the event contract while still letting individual teams manage their own subscribing infrastructure independently within their own accounts.
Testing Filter Policies Before Production Rollout
SNS provides a dry-run style filter-policy testing capability that evaluates a sample message against a proposed filter policy without actually publishing or delivering anything — using this during CI, before a filter policy change reaches production, catches the common mistake of a typo’d attribute key or an overly narrow match condition that would otherwise silently stop deliveries.
KDesign Patterns & Anti-patterns
Fanout-to-SQS Pattern
Subscribing multiple SQS queues to one topic — each queue owned by a different consuming service — is the default, most robust SNS pattern: each consumer processes at its own pace, failures in one queue never affect another, and each queue gets its own DLQ.
Event Notification Pattern
Other AWS services (S3, CloudWatch Alarms, Auto Scaling) publish directly to SNS topics as their native notification mechanism, letting you fan a single infrastructure event out to email alerts, a Lambda-based automated response, and a logging pipeline simultaneously without writing custom glue code for each.
Request-Response Bridging via SNS
Some architectures use SNS to bridge a synchronous-feeling client request to an asynchronous backend: a request handler publishes a message, immediately returns a “processing” response to the caller, and a separate mechanism (WebSocket push, polling endpoint, or webhook) later delivers the actual result once one of the fanned-out consumers finishes its work. This pattern works well for operations that genuinely can’t complete within a synchronous request window, though it does shift the complexity of correlating the original request to its eventual result onto the application layer.
Anti-pattern
Using an SNS topic as a substitute for a queue when a single consumer needs to process messages at its own pace with guaranteed retention.
Why It Fails
SNS has no message retention or replay for a subscriber that wasn’t connected at publish time, and standard topics offer no ordering — a queue-shaped problem forced onto a pub/sub primitive loses both durability and order.
Better Approach
Subscribe an SQS queue to the topic (even with a single consumer) to get durable buffering, or skip SNS entirely and publish directly to SQS if fanout to multiple consumers was never actually needed.
Anti-pattern
Filtering messages inside every subscriber’s application code instead of using SNS filter policies.
Why It Fails
Every non-matching message still gets delivered, invoking Lambda or consuming SQS capacity for work that’s immediately discarded — wasted cost and wasted latency at scale.
Better Approach
Push routing decisions into filter policies on each subscription so non-matching messages are never delivered in the first place.
LBest Practices & Common Mistakes
Best Practices
- Attach a DLQ to every subscription that carries meaningful data, and alarm on its depth.
- Design every standard-topic subscriber to be idempotent, since duplicates are expected, not exceptional.
- Push routing logic into filter policies rather than discarding non-matching messages inside consumers.
- Enable delivery status logging while debugging, and keep aggregate CloudWatch metrics on permanently.
- Use FIFO topics only when ordering or exact-once publish semantics are a genuine requirement, not by default.
Common Mistakes
- Assuming standard-topic delivery is exactly-once and building non-idempotent consumers.
- Forgetting that HTTP/S, email, and SMS subscriptions require explicit confirmation before delivery starts.
- Publishing payloads near or over the 256 KB limit without an S3 offload pattern in place.
- Treating SNS as durable, replayable storage for a subscriber that connects after the message was published.
- Editing filter policies by hand in the console without review, causing silent delivery gaps for existing consumers.
Naming and Tagging Conventions
Topics that accumulate many subscriptions over time benefit from a consistent naming convention that encodes the event domain and environment (for example, an orders-events-prod style name) plus consistent resource tagging for cost allocation and ownership tracking — a practice that seems minor early on but becomes the difference between a quick audit and a multi-day archaeology project once a topic has a dozen cross-team subscriptions attached to it.
Reviewing Topic and Subscription Sprawl Periodically
Because adding a subscription is low-friction and doesn’t require the publisher’s involvement, topics in active use tend to accumulate subscriptions from teams that later change direction or deprecate a service without ever removing their subscription. A periodic review of subscriptions against their actual delivery metrics (a subscription with zero recent successful deliveries is a strong signal it’s stale) keeps the topic’s fanout list accurate and avoids paying for, or debugging around, dead subscriptions.
MReal-World & Industry Examples
Netflix
Has discussed pub/sub fanout patterns similar to SNS’s model for decoupling event producers from many independent internal consuming teams.
Zillow
Has described using SNS delivery-status metrics and DLQ alarms to catch degraded downstream consumers before customer impact.
Capital One
Has documented event-driven architectures using SNS fanout to decouple transaction-processing services from downstream fraud-detection and notification systems.
Duolingo
Has discussed serverless, event-driven backends where SNS-style fanout distributes user-activity events to multiple independent analytics and personalization services.
These examples reflect publicly discussed architectural patterns from AWS case studies and conference talks. Specifics of any individual company’s current internal setup are not independently verifiable here — treat them as illustrative of common patterns rather than exact current configurations.
Why This Pattern Recurs
Across streaming, real estate, fintech, and edtech, the same core need keeps showing up: one event, many independent teams that each need to react to it without coordinating deployments with each other or with the publisher. SNS’s value in each case isn’t any single feature — it’s that filter policies, per-subscription retries, and heterogeneous protocol support together let a publishing team add a new downstream consumer without ever touching the publisher’s code.
What These Companies Are Not Using SNS For
It’s worth noting the negative space too: none of these publicly discussed architectures describe using SNS as a long-lived event store, a strict processing queue for a single consumer, or a replacement for a full event-streaming platform where consumers need to replay months of history. That absence is consistent with SNS’s actual design — the pattern that recurs across industries is specifically “notify many independent listeners right now,” not “durably store and let anyone catch up later.”
Where a Different Service Would Be a Better Fit
Recognizing the boundary of SNS’s fit is as useful as recognizing where it excels. Workloads needing long-term event replay, complex stream processing, or exactly-once semantics across an entire pipeline (not just the publish step) typically reach for Kinesis Data Streams or a managed Kafka service instead. Workloads needing only a single durable consumer with no fanout requirement are usually simpler and cheaper built directly on SQS. SNS earns its place specifically at the intersection of “more than one independent consumer” and “near-real-time delivery is good enough” — outside that intersection, it’s often not the most natural tool for the job.
NFrequently Asked Questions
OSummary and Key Takeaways
Key Takeaways
- Standard topics are at-least-once, not exactly-once — every subscriber must be built to handle duplicate messages safely.
- Filter policies route messages inside SNS itself, before delivery — non-matching subscribers never see the message and never pay for processing it.
- Retry behavior and DLQ support are configured per subscription, not per topic — a failing consumer never affects the delivery guarantees of any other consumer on the same topic.
- FIFO topics trade throughput for strict ordering and dedup, scoped per message group — use them only when that guarantee is a genuine requirement.
- SNS has no message retention or replay — a subscriber must be connected at publish time, or pair SNS with a durable subscriber like SQS from the start.
- Security is enforced on both sides of a subscription — the topic policy controls who may publish and subscribe, while the subscriber’s own resource policy (SQS queue policy, Lambda resource policy) must separately allow SNS to deliver to it.
- Every subscription without a configured DLQ is a silent data-loss risk once its retries are exhausted — treat DLQ configuration as a production requirement, not an optional extra.

