Home β€Ί AWS Resources β€Ί Amazon SQS

Amazon SQS

Message queuing on AWS: Standard vs FIFO, dead-letter queues, scaling patterns, and when to use SQS vs other messaging services.

What Is SQS?

SQS is the simplest messaging service on AWS. A producer puts messages on a queue. A consumer reads messages, processes them, and deletes them. If processing fails, the message becomes visible again after a timeout and gets retried.

That's it. No routing, no topics, no filtering. Just reliable delivery with retries.

Standard vs FIFO

Standard FIFO
Throughput Unlimited 300 msg/s (3,000 with batching)
Ordering Best-effort (usually in order, not guaranteed) Strict within message group
Delivery At-least-once (possible duplicates) Exactly-once
Cost $0.40/million requests $0.50/million requests
Use case High-volume processing, fan-out Financial transactions, ordered workflows

Default to Standard. Design your consumers to be idempotent (processing the same message twice is safe), and you get unlimited throughput. FIFO is for when ordering within a group genuinely matters and you can't tolerate duplicates.

Dead-Letter Queues

When a message fails processing repeatedly, it moves to a dead-letter queue (DLQ) instead of retrying forever:

Main Queue (maxReceiveCount: 3)
  β†’ Success: message deleted
  β†’ Failure: retried up to 3 times
  β†’ After 3 failures: moved to DLQ

The DLQ is just another SQS queue. You need a strategy for what happens next:

  • Manual investigation (look at DLQ messages, fix the bug, redrive)
  • Automated redrive (after deploying a fix, push DLQ messages back to the main queue)
  • Alerting (alarm when DLQ depth > 0)

AWS now supports native redrive from the console and API. No manual copy/delete loops.

SQS vs SNS vs EventBridge

These three get confused constantly:

SQS SNS EventBridge
Pattern Point-to-point queue Pub/sub fan-out Event bus with content routing
Consumers One consumer group Multiple subscribers Multiple targets per rule
Filtering None (consumer gets everything) Attribute-based filtering Content-based pattern matching
Ordering FIFO only FIFO only No ordering guarantee
Retry Automatic (visibility timeout) Immediate retry, then DLQ Rule-level DLQ
Best for Work queues, backpressure Notifications, fan-out Decoupled microservices

Common combination: EventBridge β†’ SQS. EventBridge routes events to the right queue; SQS handles reliable processing with backpressure and retries.

Another common pattern: SNS β†’ SQS fan-out. One SNS topic with multiple SQS subscriptions. Each queue processes independently at its own pace.

Scaling Patterns

Lambda consumer

Lambda polls SQS automatically. Scales from 0 to your concurrency limit based on queue depth. The simplest pattern for serverless architectures.

Key settings:

  • Batch size: How many messages per Lambda invocation (1-10,000)
  • Batch window: Wait up to N seconds to fill a batch (reduces invocations)
  • Concurrency: Lambda scales up to 1,000 concurrent executions (configurable)
  • Report batch item failures: Only retry failed messages, not the whole batch

ECS/EC2 consumer

Long-poll from the queue in a loop. Scale the number of tasks/instances based on queue depth (CloudWatch metric: ApproximateNumberOfMessagesVisible).

Auto-scaling based on queue depth

Target: Keep messages-per-consumer below a threshold
Metric: ApproximateNumberOfMessagesVisible / DesiredCount
Target value: 10 (each instance processes 10 messages at a time)

Visibility Timeout

When a consumer reads a message, it becomes invisible to other consumers for the visibility timeout period. If the consumer doesn't delete it within that window, the message becomes visible again (and another consumer picks it up).

Set visibility timeout > your processing time. If your Lambda timeout is 60 seconds, set visibility timeout to at least 60 seconds.

CDK Example

import { Queue, DeadLetterQueue } from 'aws-cdk-lib/aws-sqs';

const dlq = new Queue(this, 'OrderDLQ', {
  queueName: 'order-processing-dlq',
  retentionPeriod: Duration.days(14),
});

const queue = new Queue(this, 'OrderQueue', {
  queueName: 'order-processing',
  visibilityTimeout: Duration.seconds(60),
  deadLetterQueue: {
    queue: dlq,
    maxReceiveCount: 3,
  },
});

// FIFO variant
const fifoQueue = new Queue(this, 'PaymentQueue', {
  queueName: 'payment-processing.fifo',
  fifo: true,
  contentBasedDeduplication: true,
  visibilityTimeout: Duration.seconds(30),
});

Cost Considerations

  • $0.40 per million requests (Standard), $0.50 per million (FIFO)
  • First 1 million requests/month are free
  • Long polling (WaitTimeSeconds: 20) reduces empty responses (and cost)
  • Batch operations count as one request (send/receive/delete up to 10 messages per request)

SQS is extremely cheap. A queue processing 10 million messages/month costs ~$4. The real cost is usually the compute (Lambda, ECS) consuming the messages, not the queue itself.

Further Reading

Looking for hands-on help? View my AWS architecture services β†’

Designing message-driven systems?

Drop me a message β€” I typically respond within one business day.