Cloud & Aws

SQS vs RabbitMQ on Amazon MQ: The Message Rate Where Cost Flips

Table of Contents

Every comparison of SQS vs RabbitMQ eventually says the same thing about cost: SQS is cheap at low volume, a broker is cheaper at high volume. That is true, and it does not help anyone, because nobody says where “high” starts. This post is for the backend engineer on AWS who already knows both tools work and needs to know which one costs less at their message rate, before the architecture review rather than after the first bill.

Every rate below comes from the AWS Price List API for us-east-1, read on 13 November 2026. A short awk script turns those rates into monthly bills at 1, 10, 100, 1,000 and 10,000 messages per second, for two message sizes and two batch sizes. It then solves for the exact rate where each broker size becomes cheaper than SQS. The script and its raw output are printed in full, so you can rerun them when a price moves.

Prices read 2026-11-13
Region: US East (N. Virginia), on-demand, no Savings Plans, no free trial credits
AWS Price List offer files, us-east-1:
  AWSQueueService   published 2026-11-11T15:35:51Z
  AmazonMQ          published 2026-09-11T12:44:56Z
  AmazonMSK         published 2026-11-11T00:23:59Z
  AWSDataTransfer   published 2026-11-11T19:19:41Z
Calculator: GNU Awk 5.0.0 in Git Bash 5.2.37 on Windows 11 Pro
Month length: 730 hours (2,628,000 seconds)
Excluded: NAT gateway and internet transfer, CloudWatch, support plans, engineer time

The vendor pages behind these files are Amazon SQS pricing, Amazon MQ pricing and Amazon MSK pricing. None of them shows a last-updated date, so the offer file publication dates above are the honest timestamps.

The Short Answer

Unbatched, SQS standard costs more than a three-node RabbitMQ cluster on mq.m7g.large at about 209 messages per second. With batches of ten, the same crossover moves to about 2,090 messages per second, ten times higher. For 32 KB messages with clients spread across three Availability Zones, batched SQS never costs more, because the broker’s cross-AZ traffic alone outgrows the SQS bill.

In other words, batching decides the answer more than the choice of service does. Most teams that think they have outgrown SQS are paying for unbatched calls.

Where the Prices Came From

The AWS pricing pages render from the same offer files the Price List API serves. Reading the JSON directly sidesteps rate tables that load through JavaScript and summaries that round. This PowerShell pulls one file and prints every on-demand rate:

# Downloads the us-east-1 offer file and prints usage type, unit, price and description
$s = 'AWSQueueService'   # also run with 'AmazonMQ', 'AmazonMSK' and 'AWSDataTransfer'
$u = "https://pricing.us-east-1.amazonaws.com/offers/v1.0/aws/$s/current/us-east-1/index.json"
$j = Invoke-RestMethod -Uri $u
$j.publicationDate
foreach ($sku in $j.terms.OnDemand.PSObject.Properties) {
  $a = $j.products.($sku.Name).attributes
  foreach ($t in $sku.Value.PSObject.Properties) {
    foreach ($pd in $t.Value.priceDimensions.PSObject.Properties) {
      $v = $pd.Value
      '{0} | {1} | {2} | {3}-{4} | {5}' -f $a.usagetype, $v.unit, $v.pricePerUnit.USD,
        $v.beginRange, $v.endRange, $v.description
    }
  }
}

SQS Rates

The full SQS output is eight lines, pasted unedited:

Global-Requests | Requests | 0.0000000000 | 0-1000000 | First 1,000,000 Amazon SQS Requests per month are free
Requests-RBP | Requests | 0.0000004000 | 0-100000000000 | $0.40 per million Amazon SQS standard requests in Tier1 in US East (N Virginia)
Requests-RBP | Requests | 0.0000003000 | 100000000000-200000000000 | $0.30 per million Amazon SQS standard requests in Tier2 in US East (N Virginia)
Requests-RBP | Requests | 0.0000002400 | 200000000000-Inf | $0.24 per million Amazon SQS standard requests in Tier3 in US East (N Virginia)
Requests-Fair-RBP | Requests | 0.0000001000 | 0-Inf | $0.10 per million Amazon SQS fair queue requests in US East (N. Virginia)
Requests-FIFO-RBP | Requests | 0.0000005000 | 0-100000000000 | $0.50 per million Amazon SQS FIFO requests in Tier1 in US East (N Virginia)
Requests-FIFO-RBP | Requests | 0.0000004000 | 100000000000-200000000000 | $0.40 per million Amazon SQS FIFO requests in Tier2 in US East (N Virginia)
Requests-FIFO-RBP | Requests | 0.0000003500 | 200000000000-Inf | $0.35 per million Amazon SQS FIFO requests in Tier3 in US East (N Virginia)

Tier 2 starts at 100 billion requests a month. The busiest workload in this post, 10,000 unbatched messages per second, makes about 79 billion, so every bill below sits in tier 1.

Amazon MQ for RabbitMQ Rates

The AmazonMQ file lists several dozen rates, most of them for ActiveMQ or older m5 instances. These are the RabbitMQ lines the calculator uses:

USE1-RabbitMQ-Single-InstanceUsage:mq.m7g.large | Hrs | 0.2734000000 | 0-Inf | $0.2734 per Hrs for RabbitMQ-Single-InstanceUsage:mq.m7g.large in US East (N. Virginia)
USE1-RabbitMQ-3-InstanceUsage:mq.m7g.large | Hrs | 0.8201000000 | 0-Inf | $0.8201 per Hrs for RabbitMQ-3-InstanceUsage:mq.m7g.large in US East (N. Virginia)
USE1-RabbitMQ-3-InstanceUsage:mq.m7g.xlarge | Hrs | 1.6402000000 | 0-Inf | $1.6402 per Hrs for RabbitMQ-3-InstanceUsage:mq.m7g.xlarge in US East (N. Virginia)
USE1-RabbitMQ-3-InstanceUsage:mq.m7g.2xl | Hrs | 3.2803000000 | 0-Inf | $3.2803 per Hrs for RabbitMQ-3-InstanceUsage:mq.m7g.2xl in US East (N. Virginia)
USE1-TimedStorage-RabbitMQ-ByteHrs | GB-Mo | 0.1000000000 | 0-Inf | Storage (Amazon EBS) used by RabbitMQ brokers (GB-months) in US East (N. Virginia)

Note that the three-instance price is per cluster, not per node: $0.8201 is three times the single-instance $0.2734, rounded. Also, neither the AmazonMQ nor the AmazonMSK file carries any reserved terms, so there is no commitment discount to model.

MSK and Data Transfer Rates

MSK appears as a reference point, because the next question after “SQS or RabbitMQ” is often “or Kafka”. The broker and storage lines, followed by the intra-region transfer lines from AWSDataTransfer:

USE1-Kafka.m7g.large | hours | 0.2040000000 | 0-Inf | $0.204 per broker hour for Kafka.m7g.large in US East (N. Virginia)
USE1-Kafka.Storage.GP2 | GB-Mo | 0.1000000000 | 0-Inf | $0.10 per GB-Mo for storage in US East (N. Virginia)
DataTransfer-Regional-Bytes | IntraRegion | US East (N. Virginia) -> US East (N. Virginia) | 0.0100000000 | $0.010 per GB - regional data transfer - in/out/between EC2 AZs or using elastic IPs or ELB
USE1-DataTransfer-xAZ-Out-Bytes | IntraRegion-xAZ-Out | US East (N. Virginia) -> US East (N. Virginia) | 0.0000000000 | $0.00 per GB - regional data transfer - in/out/between EC2 Azs or using elastic IPs or ELB
USE1-DataTransfer-xAZ-In-Bytes | IntraRegion-xAZ-In | US East (N. Virginia) -> US East (N. Virginia) | 0.0000000000 | $0.00 per GB - regional data transfer - in/out/between EC2 Azs or using elastic IPs or ELB

The transfer file is ambiguous on its own: a $0.010 regional line sits next to two $0.00 cross-AZ lines. The EC2 on-demand pricing page settles it in plain words: data “across Availability Zones in the same AWS Region is charged at $0.01/GB in each direction.” The calculator therefore uses $0.02 per GB that crosses an AZ.

SQS vs RabbitMQ: What Each One Bills

The two services meter completely different things, which is why their bills cross at all. This table is the short answer to “what am I paying for”:

SQS standardSQS FIFOAmazon MQ for RabbitMQMSK provisioned
Fixed feenonenoneper broker-hourper broker-hour
Per-message fee$0.40 per million requests$0.50 per million requestsnonenone
Free tier1M requests a monthshared with standardnonenone
Storageincludedincluded$0.10 per GB-month of EBS$0.10 per GB-month
In-region transferfreefreestandard cross-AZ ratesstandard cross-AZ rates
Transfer inside the clusternot applicablenot applicablefreefree for replication

The cluster transfer rows come from the vendor pages. Amazon MQ states that “for Amazon MQ for RabbitMQ clusters, there are no additional charges for data transfer fees within the cluster”, while also charging “standard AWS data transfer charges for data transferred in and out of Amazon MQ”. SQS, by contrast, says it does not charge for data transfer “if all resources are in the same AWS region.” Three details decide almost every number below.

Why One Message Costs Three SQS Requests

An SQS message is not one request. The producer calls SendMessage, the consumer calls ReceiveMessage, and after processing it calls DeleteMessage. That is three billed requests per message, so $0.40 per million requests is really $1.20 per million messages when nothing is batched.

Batching changes the arithmetic. SendMessageBatch, ReceiveMessage with up to ten messages and DeleteMessageBatch each count once for up to ten messages. As a result, a fully batched pipeline pays 0.3 requests per message, or $0.12 per million messages.

The 64 KB Chunk Rule in SQS Pricing

Batching has a ceiling, though, and it is payload size. The SQS pricing page is explicit: “Each 64 KB chunk of a payload is billed as 1 request (for example, an API action with a 1 MiB payload is billed as 16 requests).” A batch of ten 1 KB messages is one request. A batch of ten 32 KB messages, however, is 320 KB, which bills as five.

Delete calls carry receipt handles, not payloads, so they stay at one request per batch. Consequently, a batched 32 KB pipeline pays 1.1 requests per message instead of 0.3.

Cross-AZ Traffic: The Line Broker Comparisons Skip

A highly available broker lives in three Availability Zones, and so do its clients. With clients spread evenly, two out of three connections land on a node in another AZ. Every message makes two trips, publish and consume, and each trip crosses an AZ two times in three, billed at $0.02 per GB.

For 1 KB messages that is about $0.025 per million messages, which barely registers. For 32 KB messages, it is about $0.81 per million, more than batched SQS charges for the whole message lifecycle. SQS has no such line, because in-region transfer to SQS is free.

The Workload Assumptions

A price comparison is only as honest as its assumptions, so here they are in full:

  1. Message rate: a steady 1, 10, 100, 1,000 or 10,000 messages per second, all month.
  2. Message size: 1 KB, a typical JSON event, and 32 KB, a fat event carrying a full order or document.
  3. SQS batching: batch size 1 (every call carries one message) and batch size 10 (every call is full).
  4. SQS requests: send, receive and delete each billed, with the 1 million monthly free requests subtracted once.
  5. RabbitMQ storage: 200 GB of EBS per node, the default limit that AWS’s own pricing example uses, which bills $60 a month for a three-node cluster.
  6. MSK: three kafka.m7g.large brokers with 100 GB each, as a reference column.
  7. Cross-AZ: clients in three AZs, two-thirds of traffic crossing on both publish and consume, shown as its own column because many setups pin clients differently.

Long-polling idle consumers are left out. Specifically, one consumer waiting 20 seconds per ReceiveMessage on an empty queue makes 131,400 requests a month, which the free tier absorbs for up to seven idle pollers.

The Cost Script

The calculator is a single awk program, so it runs in any Bash, including Git Bash on Windows, with no installs. Every rate sits at the top with the offer file it came from:

#!/usr/bin/env bash
# queue-cost.sh: monthly cost of SQS vs RabbitMQ on Amazon MQ vs MSK, us-east-1.
# Rates from the AWS Price List API (us-east-1 offer files) read 2026-11-13.
awk 'BEGIN {
  SQS_STD = 0.0000004; SQS_FIFO = 0.0000005; SQS_FREE = 1000000;  # AWSQueueService
  CHUNK_KB = 64;                                    # each 64 KB of payload = 1 request
  MQ_1 = 0.2734;  MQ_3L = 0.8201;                   # AmazonMQ: single m7g.large, 3-node m7g.large
  MQ_3XL = 1.6402; MQ_32XL = 3.2803;                # 3-node m7g.xlarge, 3-node m7g.2xlarge
  MQ_GB = 0.10; MQ_VOL = 200;                       # EBS GB-month, default 200 GB per node
  MSK_L = 0.204; MSK_GB = 0.10; MSK_VOL = 100;      # AmazonMSK: kafka.m7g.large, 100 GB each
  XAZ_GB = 0.02; XAZ_SHARE = 2 / 3;                 # $0.01 out + $0.01 in, 2 of 3 AZs cross
  HRS = 730; SECS = HRS * 3600;

  mq1   = MQ_1 * HRS + 1 * MQ_VOL * MQ_GB
  mq3   = MQ_3L * HRS + 3 * MQ_VOL * MQ_GB
  mq3xl = MQ_3XL * HRS + 3 * MQ_VOL * MQ_GB
  mq32x = MQ_32XL * HRS + 3 * MQ_VOL * MQ_GB
  msk   = 3 * MSK_L * HRS + 3 * MSK_VOL * MSK_GB

  printf "Fixed monthly cost: MQ single m7g.large %.2f | MQ 3-node m7g.large %.2f | 3-node m7g.xlarge %.2f | 3-node m7g.2xlarge %.2f | MSK 3x m7g.large %.2f\n\n",
    mq1, mq3, mq3xl, mq32x, msk

  split("1 32", KB, " "); split("1 10 100 1000 10000", RATE, " ")
  for (k = 1; k <= 2; k++) {
    kb = KB[k]
    printf "Message size %d KB\n", kb
    printf "%7s %14s | %9s %9s %9s %9s | %9s %9s %9s | %9s\n", "msg/s", "msgs/month",
      "SQS b1", "SQS b10", "FIFO b1", "FIFO b10", "MQ 1x", "MQ 3x", "MSK 3x", "xAZ"
    for (i = 1; i <= 5; i++) {
      r = RATE[i]; m = r * SECS
      printf "%7d %14d | %9.2f %9.2f %9.2f %9.2f | %9.2f %9.2f %9.2f | %9.2f\n", r, m,
        sqs(m, kb, 1, SQS_STD), sqs(m, kb, 10, SQS_STD), sqs(m, kb, 1, SQS_FIFO), sqs(m, kb, 10, SQS_FIFO),
        mq1, mq3, msk, xaz(m, kb)
    }
    printf "\n"
  }

  split("MQ single m7g.large|MQ 3-node m7g.large|MQ 3-node m7g.xlarge|MQ 3-node m7g.2xlarge|MSK 3x m7g.large", NAME, "|")
  FIX[1] = mq1; FIX[2] = mq3; FIX[3] = mq3xl; FIX[4] = mq32x; FIX[5] = msk
  for (k = 1; k <= 2; k++) {
    kb = KB[k]
    printf "Crossover: messages per second where SQS costs the same as the broker (%d KB messages)\n", kb
    printf "%-26s %10s %10s %10s %10s\n", "broker (with storage)", "SQS b1", "SQS b10", "FIFO b1", "FIFO b10"
    for (b = 1; b <= 5; b++) for (x = 0; x <= 1; x++) {
      printf "%-26s %10s %10s %10s %10s\n", NAME[b] (x ? " +xAZ" : ""),
        fmt(cross(FIX[b], x, kb, 1, SQS_STD)), fmt(cross(FIX[b], x, kb, 10, SQS_STD)),
        fmt(cross(FIX[b], x, kb, 1, SQS_FIFO)), fmt(cross(FIX[b], x, kb, 10, SQS_FIFO))
    }
    printf "\n"
  }
}

function fmt(v) { return v < 0 ? "never" : sprintf("%.0f", v) }

# SQS bill: send and receive pay per 64 KB chunk of the batch payload, delete pays 1 per batch.
function sqs(msgs, kb, batch, price,    chunks, reqs) {
  chunks = int((kb * batch + CHUNK_KB - 1) / CHUNK_KB)
  reqs = msgs / batch * (2 * chunks + 1)
  reqs = reqs > SQS_FREE ? reqs - SQS_FREE : 0
  return reqs * price
}
# Cross-AZ bytes: every message crosses on publish and on consume, 2 of 3 times.
function xaz(msgs, kb) { return msgs * kb / 1048576 * 2 * XAZ_SHARE * XAZ_GB }
# Bisection on msg/s until the SQS bill equals the broker bill.
function cross(fixed, withx, kb, batch, price,    lo, hi, mid, n, d) {
  lo = 0; hi = 1000000
  for (n = 0; n < 100; n++) {
    mid = (lo + hi) / 2
    d = sqs(mid * SECS, kb, batch, price) - fixed - (withx ? xaz(mid * SECS, kb) : 0)
    if (d > 0) hi = mid; else lo = mid
  }
  return mid >= 999999 ? -1 : mid
}'

The crossover is a bisection rather than a closed formula, because the free tier and the chunk rounding make the SQS bill piecewise. When SQS never overtakes the broker below a million messages per second, the script prints “never”. Moreover, every rate is a named constant, so a price change means editing one line and rerunning.

Raw Output of the Cost Script

The output below is pasted unedited, all amounts in US dollars per month:

Fixed monthly cost: MQ single m7g.large 219.58 | MQ 3-node m7g.large 658.67 | 3-node m7g.xlarge 1257.35 | 3-node m7g.2xlarge 2454.62 | MSK 3x m7g.large 476.76

Message size 1 KB
  msg/s     msgs/month |    SQS b1   SQS b10   FIFO b1  FIFO b10 |     MQ 1x     MQ 3x    MSK 3x |       xAZ
      1        2628000 |      2.75      0.00      3.44      0.00 |    219.58    658.67    476.76 |      0.07
     10       26280000 |     31.14      2.75     38.92      3.44 |    219.58    658.67    476.76 |      0.67
    100      262800000 |    314.96     31.14    393.70     38.92 |    219.58    658.67    476.76 |      6.68
   1000     2628000000 |   3153.20    314.96   3941.50    393.70 |    219.58    658.67    476.76 |     66.83
  10000    26280000000 |  31535.60   3153.20  39419.50   3941.50 |    219.58    658.67    476.76 |    668.33

Message size 32 KB
  msg/s     msgs/month |    SQS b1   SQS b10   FIFO b1  FIFO b10 |     MQ 1x     MQ 3x    MSK 3x |       xAZ
      1        2628000 |      2.75      0.76      3.44      0.95 |    219.58    658.67    476.76 |      2.14
     10       26280000 |     31.14     11.16     38.92     13.95 |    219.58    658.67    476.76 |     21.39
    100      262800000 |    314.96    115.23    393.70    144.04 |    219.58    658.67    476.76 |    213.87
   1000     2628000000 |   3153.20   1155.92   3941.50   1444.90 |    219.58    658.67    476.76 |   2138.67
  10000    26280000000 |  31535.60  11562.80  39419.50  14453.50 |    219.58    658.67    476.76 |  21386.72

Crossover: messages per second where SQS costs the same as the broker (1 KB messages)
broker (with storage)          SQS b1    SQS b10    FIFO b1   FIFO b10
MQ single m7g.large                70        698         56        558
MQ single m7g.large +xAZ           71        885         57        672
MQ 3-node m7g.large               209       2090        167       1672
MQ 3-node m7g.large +xAZ          214       2652        170       2014
MQ 3-node m7g.xlarge              399       3988        319       3191
MQ 3-node m7g.xlarge +xAZ         407       5061        325       3842
MQ 3-node m7g.2xlarge             778       7785        623       6228
MQ 3-node m7g.2xlarge +xAZ        795       9878        634       7500
MSK 3x m7g.large                  151       1513        121       1211
MSK 3x m7g.large +xAZ             155       1920        123       1458

Crossover: messages per second where SQS costs the same as the broker (32 KB messages)
broker (with storage)          SQS b1    SQS b10    FIFO b1   FIFO b10
MQ single m7g.large                70        190         56        152
MQ single m7g.large +xAZ          217      never        122      never
MQ 3-node m7g.large               209        570        167        456
MQ 3-node m7g.large +xAZ          649      never        366      never
MQ 3-node m7g.xlarge              399       1088        319        870
MQ 3-node m7g.xlarge +xAZ        1239      never        698      never
MQ 3-node m7g.2xlarge             778       2123        623       1699
MQ 3-node m7g.2xlarge +xAZ       2419      never       1361      never
MSK 3x m7g.large                  151        413        121        330
MSK 3x m7g.large +xAZ             470      never        265      never

Monthly Cost at 1 KB Messages

For small JSON events, the comparison is mostly SQS request charges against a flat broker fee. US dollars per month, with the three-node RabbitMQ cluster on mq.m7g.large including its cross-AZ line:

Messages per secondSQS unbatchedSQS batched (10)RabbitMQ 3-node m7g.largeRabbitMQ + cross-AZ
12.750.00658.67658.74
1031.142.75658.67659.34
100314.9631.14658.67665.35
1,0003,153.20314.96658.67725.50
10,00031,535.603,153.20658.671,327.00

Below 100 messages per second, the broker loses badly in either mode. At 10 messages per second, for instance, batched SQS costs $2.75 against $658.67. At 1,000 messages per second the picture splits: unbatched SQS is almost five times the cluster, while batched SQS is still under half of it.

Keep in mind that the broker columns assume one cluster handles the load. AWS does not publish a messages-per-second figure for any RabbitMQ instance size, so whether an m7g.large cluster sustains 10,000 messages per second is a question this post cannot answer from a price list.

Monthly Cost at 32 KB Messages

Larger messages change both sides. SQS batches stop collapsing into one request, and the broker’s cross-AZ line grows with every byte:

Messages per secondSQS unbatchedSQS batched (10)RabbitMQ 3-node m7g.largeRabbitMQ + cross-AZ
12.750.76658.67660.81
1031.1411.16658.67680.06
100314.96115.23658.67872.54
1,0003,153.201,155.92658.672,797.34
10,00031,535.6011,562.80658.6722,045.39

The unbatched SQS column is identical to the 1 KB table, because a 32 KB message still fits in a single 64 KB chunk. The batched column, by contrast, is almost four times higher. Meanwhile, the cross-AZ line at 10,000 messages per second is $21,386.72, more than thirty times the cluster itself.

At What Message Rate Does RabbitMQ Become Cheaper Than SQS?

For 1 KB messages, a three-node RabbitMQ cluster on Amazon MQ mq.m7g.large becomes cheaper than SQS standard at about 209 messages per second when SQS calls are unbatched. With full batches of ten, the crossover moves to about 2,090 messages per second, roughly 5.5 billion messages a month.

The full table, 1 KB messages, cross-AZ traffic included:

BrokerSQS unbatchedSQS batchedFIFO unbatchedFIFO batched
RabbitMQ single m7g.large7188557672
RabbitMQ 3-node m7g.large2142,6521702,014
RabbitMQ 3-node m7g.xlarge4075,0613253,842
RabbitMQ 3-node m7g.2xlarge7959,8786347,500
MSK 3x kafka.m7g.large1551,9201231,458

Read the rows as “if my load needs this broker size”. If a three-node m7g.xlarge cluster is what your throughput requires, batched SQS stays cheaper up to about 5,000 messages per second. FIFO crosses earlier in every row, because its requests cost 25% more.

Why 32 KB Messages Never Cross Over When Batched

With 32 KB messages and clients in three AZs, the batched SQS columns read “never” for every broker. The reason is per-message arithmetic. Batched SQS charges 1.1 requests per 32 KB message, about $0.44 per million. The broker’s cross-AZ traffic charges about $0.81 per million for the same messages. Since the broker’s marginal cost per message is higher than SQS’s, adding traffic only widens the gap.

That result depends entirely on the cross-AZ assumption. If every client sits in the same AZ as a single-instance broker, the cross-AZ line drops to zero and the crossover returns to 190 messages per second. That setup, however, gives up the availability most teams bought a managed broker for.

What This Price Comparison Does Not Measure

Several things that matter in production are out of scope, and each one can move the crossover:

  • Broker throughput. The Amazon MQ sizing guidelines and resource limit tables give connections, channels and queues per instance, but no messages per second. No broker was deployed for this post.
  • Protocol overhead. AMQP frames, headers and acknowledgements add bytes beyond the payload, so the cross-AZ figures are a lower bound.
  • Kafka fetch-from-follower. MSK consumers configured with client.rack can read from a replica in their own AZ, which removes the consume half of the cross-AZ line for the MSK rows.
  • People. A broker needs someone who understands quorum queues, memory alarms and upgrade windows. SQS needs none of that, and no price list includes it.
  • Commitment and private pricing. The AmazonMQ and AmazonMSK offer files carry no reserved terms, and negotiated discounts on any of these services are not public.

Batching SQS in Node.js

Since batching moves the crossover by a factor of ten, it is the first change to make before any migration. This consumer receives up to ten messages per call with long polling and deletes them in one batch:

import {
  SQSClient,
  ReceiveMessageCommand,
  DeleteMessageBatchCommand,
} from '@aws-sdk/client-sqs';

const client = new SQSClient({});
const QUEUE_URL = process.env.QUEUE_URL;

export async function pollOnce(handleMessage) {
  const { Messages = [] } = await client.send(new ReceiveMessageCommand({
    QueueUrl: QUEUE_URL,
    MaxNumberOfMessages: 10,   // one billed request for up to ten messages
    WaitTimeSeconds: 20,       // long polling: empty queues cost 3 requests a minute, not thousands
  }));
  if (Messages.length === 0) return 0;

  const done = [];
  for (const msg of Messages) {
    try {
      await handleMessage(JSON.parse(msg.Body));
      done.push({ Id: msg.MessageId, ReceiptHandle: msg.ReceiptHandle });
    } catch (err) {
      // Leave it undeleted: it reappears after the visibility timeout, then goes to the DLQ
      console.error(`Failed ${msg.MessageId}:`, err);
    }
  }

  if (done.length > 0) {
    const res = await client.send(new DeleteMessageBatchCommand({ QueueUrl: QUEUE_URL, Entries: done }));
    // Batch calls succeed as a whole even when single entries fail, so check each one
    for (const f of res.Failed ?? []) console.error(`Delete failed for ${f.Id}: ${f.Code}`);
  }
  return Messages.length;
}

The partial-failure check matters as much as the batching. DeleteMessageBatch returns HTTP 200 even when individual entries fail, and an undeleted message comes back as a duplicate. On the producer side, SendMessageBatchCommand works the same way with a Failed array that needs the same loop.

When to Use Amazon MQ for RabbitMQ

  • Your sustained rate sits well above the crossover for the cluster size you need, and your messages are small enough that cross-AZ traffic stays a minor line.
  • You depend on AMQP features SQS lacks: topic exchanges with routing keys, per-message priorities, or many consumers on one exchange without an SNS fan-out.
  • You are lifting an existing RabbitMQ workload to AWS and rewriting producers and consumers for SQS would cost more engineering time than the broker costs in a year.
  • Consumers need push delivery with prefetch limits instead of polling.

When NOT to Use Amazon MQ for RabbitMQ

  • Your traffic is under about 70 messages per second. Below that even a single-instance broker costs more than unbatched SQS, and a three-node cluster costs more up to about 209.
  • Messages are tens of kilobytes and clients run in several AZs. The cross-AZ line can cost more than the broker and more than batched SQS.
  • Load is spiky with long idle stretches. SQS bills nothing for an idle queue beyond long polls, while a broker bills every hour.
  • Nobody on the team wants to own broker upgrades, memory alarms and queue-length policies.

Common Mistakes When Pricing SQS vs RabbitMQ

  • Comparing unbatched SQS against a broker. Batching moves the crossover ten times higher, and it is a code change, not a migration.
  • Counting one SQS request per message. Send, receive and delete are three, so $0.40 per million requests is $1.20 per million messages.
  • Ignoring the 64 KB chunk rule. Ten 32 KB messages in one batch bill as five requests, not one.
  • Leaving out cross-AZ transfer for the broker. SQS in-region transfer is free, broker traffic is not, and at 32 KB the gap reverses the conclusion.
  • Using message group IDs on a standard queue without noticing the fair queue line. The pricing page says those requests are “charged both fair queue rates and standard queue rates”, an extra $0.10 per million.
  • Sizing the broker by price instead of load. A cluster that is cheaper on paper but runs at its memory alarm costs an outage, not a saving.

A Realistic Scenario: The Queue Bill That Prompted a Migration Plan

Consider a small platform team running an order-events pipeline on SQS standard for a mid-sized e-commerce product. Traffic has grown to a few hundred messages per second at peak, and the SQS line now runs into several hundred dollars a month. Someone proposes moving to a three-node RabbitMQ cluster on Amazon MQ, citing the fixed $658.67 a month as a ceiling.

Before approving a multi-week migration, the team checks the consumers. They call ReceiveMessage with the default of one message, and each handler deletes its own message. Switching to ten-message receives and batched deletes, plus SendMessageBatch on the producers, cuts the request count by roughly a factor of ten on this post’s numbers. At 300 messages per second, that takes the bill from around $946 a month to under $95.

The broker migration gets shelved. Not because RabbitMQ is worse, but because the trigger for it was a cost problem that a two-day change solved. The team keeps the crossover table instead, and revisits it if sustained traffic approaches 2,000 messages per second.

How This Fits With the Rest of Your Messaging Stack

Cost is one axis of the choice. For ordering guarantees, replay, fan-out and operational load across all three options, the RabbitMQ vs Kafka vs SQS comparison covers the feature side this post skips. Whichever queue you pick, consumers that fall behind need a plan, and the guide on backpressure patterns for queues covers what to do when producers outrun them.

Publishing to a queue from inside a database transaction is a second source of duplicate and lost messages, and the transactional outbox pattern solves it on both SQS and RabbitMQ. If the consumers run on Lambda, the per-request economics stack with the compute ones, which the Lambda vs Fargate vs EC2 cost comparison prices the same way. For more line items worth auditing on the same bill, see the AWS cost optimization tips.

Conclusion

On SQS vs RabbitMQ cost, the crossover is real but higher than most teams assume. A three-node Amazon MQ cluster on mq.m7g.large beats unbatched SQS at about 209 messages per second, and batched SQS at about 2,090. For large messages with clients across AZs, batched SQS may never lose at all.

Batch your SQS calls first, then rerun the script with your own rate and message size before planning a migration. Prices were read on 13 November 2026 and change without notice, so rerun the numbers before quoting them.