← Back to DevBytes

SQS vs Pub/Sub: A Comprehensive Comparison for 2026

SQS vs Pub/Sub: A Comprehensive Comparison for 2026

As distributed systems continue to dominate modern application architecture in 2026, message brokers have become the backbone of decoupled, scalable microservices. Two of the most widely adopted managed messaging services are Amazon Simple Queue Service (SQS) and Google Cloud Pub/Sub. While both solve similar problems—reliable asynchronous communication between services—their design philosophies, feature sets, and operational characteristics differ in ways that can significantly impact your architecture. This tutorial provides a deep, practical comparison to help you choose the right tool for your workload.

What Are SQS and Pub/Sub?

Amazon SQS is a fully managed message queuing service that has been a cornerstone of AWS since 2004. It is fundamentally a point-to-point queue: producers send messages to a queue, and consumers pull messages one at a time. Each message is delivered to exactly one consumer and deleted after successful processing. SQS offers two queue types: Standard (at-least-once delivery, best-effort ordering, nearly unlimited throughput) and FIFO (exactly-once processing, strict ordering within message groups, 300 messages per second per group by default).

Google Cloud Pub/Sub is a fully managed, scalable, real-time messaging service designed for both streaming analytics and event-driven architectures. Unlike SQS, Pub/Sub is a publish/subscribe model: publishers send messages to topics, and multiple subscribers receive copies independently. Pub/Sub offers at-least-once delivery and supports ordering through message ordering keys. It also provides exactly-once delivery as a generally available feature in 2026, closing a long-standing gap with SQS FIFO.

Why the Comparison Matters in 2026

The messaging landscape has evolved rapidly. In 2026, teams are building event-driven architectures that must handle billions of events daily, support multi-region failover, integrate with serverless compute, and maintain strict compliance requirements. Choosing the wrong messaging primitive can lead to message loss, duplicate processing, scaling bottlenecks, or unexpected cost overruns. Understanding the nuanced differences between SQS and Pub/Sub is no longer optional—it is an architectural decision with long-term consequences.

Key considerations include delivery semantics, ordering guarantees, fan-out capabilities, integration with serverless platforms (Lambda and Cloud Functions), dead-letter handling, observability, and pricing models. Let's explore each in detail.

Core Architectural Differences

How to Use Amazon SQS

Let's walk through creating an SQS queue, sending messages, and consuming them using the AWS SDK for Python (boto3).

Creating a Standard Queue

import boto3

sqs = boto3.client('sqs', region_name='us-east-1')

response = sqs.create_queue(
    QueueName='order-processing-queue',
    Attributes={
        'VisibilityTimeout': '60',
        'MessageRetentionPeriod': '1209600',
        'DelaySeconds': '0'
    }
)

queue_url = response['QueueUrl']
print(f"Queue created: {queue_url}")

Sending Messages

import json

message_body = json.dumps({
    'order_id': 'ORD-2026-001',
    'customer_id': 'CUST-789',
    'total': 149.99,
    'items': ['SKU-100', 'SKU-200']
})

sqs.send_message(
    QueueUrl=queue_url,
    MessageBody=message_body,
    MessageAttributes={
        'OrderType': {
            'DataType': 'String',
            'StringValue': 'PREMIUM'
        }
    }
)

Consuming and Deleting Messages

while True:
    messages = sqs.receive_message(
        QueueUrl=queue_url,
        MaxNumberOfMessages=10,
        WaitTimeSeconds=20,
        MessageAttributeNames=['All']
    )

    for msg in messages.get('Messages', []):
        try:
            order = json.loads(msg['Body'])
            process_order(order)
            sqs.delete_message(
                QueueUrl=queue_url,
                ReceiptHandle=msg['ReceiptHandle']
            )
        except Exception as e:
            print(f"Processing failed: {e}")
            # Message will become visible again after visibility timeout

Creating a FIFO Queue with Message Groups

fifo_response = sqs.create_queue(
    QueueName='order-processing-queue.fifo',
    Attributes={
        'FifoQueue': 'true',
        'ContentBasedDeduplication': 'true',
        'VisibilityTimeout': '60'
    }
)

fifo_url = fifo_response['QueueUrl']

sqs.send_message(
    QueueUrl=fifo_url,
    MessageBody=json.dumps({'order_id': 'ORD-2026-002'}),
    MessageGroupId='CUSTOMER-789',
    MessageDeduplicationId='ORD-2026-002'
)

How to Use Google Cloud Pub/Sub

Now let's implement the same workflow using the Google Cloud Pub/Sub Python client library.

Creating a Topic and Subscription

from google.cloud import pubsub_v1

publisher = pubsub_v1.PublisherClient()
subscriber = pubsub_v1.SubscriberClient()

project_id = 'my-gcp-project-2026'
topic_path = publisher.topic_path(project_id, 'order-processing-topic')
subscription_path = subscriber.subscription_path(project_id, 'order-processing-sub')

publisher.create_topic(request={'name': topic_path})

subscriber.create_subscription(
    request={
        'name': subscription_path,
        'topic': topic_path,
        'ack_deadline_seconds': 60,
        'message_retention_duration': {'seconds': 604800},
        'retain_acked_messages': False
    }
)

Publishing Messages

import json

order_data = {
    'order_id': 'ORD-2026-001',
    'customer_id': 'CUST-789',
    'total': 149.99,
    'items': ['SKU-100', 'SKU-200']
}

future = publisher.publish(
    topic_path,
    json.dumps(order_data).encode('utf-8'),
    order_type='PREMIUM'
)
message_id = future.result()
print(f"Published message ID: {message_id}")

Publishing with Ordering Keys

future = publisher.publish(
    topic_path,
    json.dumps({'order_id': 'ORD-2026-002'}).encode('utf-8'),
    ordering_key='CUSTOMER-789'
)
future.result()

Consuming Messages with a Callback

def callback(message):
    try:
        order = json.loads(message.data.decode('utf-8'))
        process_order(order)
        message.ack()
    except Exception as e:
        print(f"Processing failed: {e}")
        message.nack()

streaming_pull = subscriber.subscribe(
    subscription_path,
    callback=callback,
    flow_control=pubsub_v1.types.FlowControl(max_messages=100)
)

import threading
threading.Event().wait()

Dead-Letter Handling

Both services support dead-letter queues (DLQs), but the configuration differs significantly.

SQS Dead-Letter Queue

# Create the DLQ first
dlq = sqs.create_queue(QueueName='order-dlq')
dlq_arn = sqs.get_queue_attributes(
    QueueUrl=dlq['QueueUrl'],
    AttributeNames=['QueueArn']
)['Attributes']['QueueArn']

# Configure redrive policy on the main queue
import json
redrive_policy = json.dumps({
    'deadLetterTargetArn': dlq_arn,
    'maxReceiveCount': '5'
})

sqs.set_queue_attributes(
    QueueUrl=queue_url,
    Attributes={'RedrivePolicy': redrive_policy}
)

Pub/Sub Dead-Letter Topic

from google.cloud import pubsub_v1
from google.cloud.pubsub_v1.types import DeadLetterPolicy

dlq_topic_path = publisher.topic_path(project_id, 'order-dlq-topic')
publisher.create_topic(request={'name': dlq_topic_path})

subscriber.update_subscription(
    request={
        'subscription': {
            'name': subscription_path,
            'dead_letter_policy': DeadLetterPolicy(
                dead_letter_topic=dlq_topic_path,
                max_delivery_attempts=5
            )
        },
        'update_mask': {'paths': ['dead_letter_policy']}
    }
)

Serverless Integration

In 2026, serverless integration remains a primary use case. AWS Lambda natively supports SQS as an event source with automatic batching, concurrency controls, and partial batch failure reporting. Google Cloud Functions and Cloud Run integrate with Pub/Sub through push subscriptions or eventarc triggers. A key difference: Lambda's SQS integration uses polling under the hood, while Pub/Sub push delivers messages via HTTP POST to your endpoint, which can reduce latency but requires your service to be publicly or privately reachable.

Lambda Handler for SQS

import json

def lambda_handler(event, context):
    for record in event['Records']:
        order = json.loads(record['body'])
        try:
            process_order(order)
        except Exception as e:
            # With partial batch response enabled, only failed messages retry
            raise e
    return {'statusCode': 200}

Cloud Function Handler for Pub/Sub

import json
import base64

def process_pubsub_event(event, context):
    pubsub_message = base64.b64decode(event['data']).decode('utf-8')
    order = json.loads(pubsub_message)
    process_order(order)

Performance and Scalability

SQS Standard queues offer virtually unlimited throughput with no configuration. FIFO queues are limited to 300 messages per second per message group, though AWS has introduced high-throughput FIFO mode that can reach thousands of TPS with batching. Pub/Sub scales automatically and can handle millions of messages per second globally. Its push delivery model provides lower end-to-end latency (often under 100ms) compared to SQS short polling, though long polling narrows the gap considerably.

Pricing Comparison

Both services use a pay-per-use model based on requests and data volume. SQS charges per request (a single API call can batch up to 10 messages), with the first one million requests per month free. Pub/Sub charges per message volume (minimum 1 KB per message) with the first 10 GB free per month. For high-volume, small-message workloads, SQS batching often results in lower costs. For large messages or high fan-out scenarios, Pub/Sub's native 10 MB support and multi-subscription model can be more economical.

Best Practices

When to Choose Which

Choose SQS when you need simple point-to-point queuing, tight integration with the AWS ecosystem (especially Lambda, Step Functions, and EventBridge), strict per-message ordering with FIFO queues, or fine-grained control over message visibility and consumption pacing. SQS is also ideal when you want a battle-tested, predictable queuing model with minimal operational overhead.

Choose Pub/Sub when you need native fan-out to multiple independent consumers, large message payloads (up to 10 MB), global message routing, integration with BigQuery for streaming analytics, or a push-based delivery model that minimizes consumer-side polling infrastructure. Pub/Sub also excels in event-driven architectures where multiple services react to the same event independently.

Conclusion

Both Amazon SQS and Google Cloud Pub/Sub are mature, production-grade messaging services that can power the most demanding event-driven architectures in 2026. SQS remains the gold standard for simple, reliable point-to-point queuing within AWS, offering predictable semantics and deep ecosystem integration. Pub/Sub shines in scenarios requiring native fan-out, large payloads, global distribution, and tight coupling with analytics pipelines. The right choice depends less on raw feature checklists and more on your cloud strategy, communication patterns, and operational preferences. By understanding the trade-offs in delivery semantics, ordering, scaling, cost, and integration, you can architect messaging systems that are resilient, cost-effective, and ready for the demands of modern distributed applications.

— Ad —

Google AdSense will appear here after approval

← Back to all articles