ExAws.SQS
View SourceService module for ex_aws.
This is a modernized fork of the archived
ex-aws/ex_aws_sqs (last released in Jan 2023). It exists
because the upstream project stopped receiving updates while its open issues stayed unresolved.
This fork:
- Switches every operation from the legacy Query/XML protocol to the SQS JSON protocol
(ex-aws/ex_aws_sqs#34), which AWS recommends
going forward for lower latency and less client-side overhead. This also drops the
:saxy/:sweet_xmldependency entirely — one less thing to configure or upgrade. - Documents
send_message_batch/2with a runnable example (ex-aws/ex_aws_sqs#35). - Relaxes the
:hackneyversion constraint so it no longer collides with apps that have moved to hackney 4.x (ex-aws/ex_aws_sqs#36).hackneyis only used to run this library's own test suite — request execution always goes through whatever HTTP adapter your app configures forex_aws. - Adds the message-move-task operations (
start_message_move_task/2,cancel_message_move_task/1,list_message_move_tasks/2) andListQueues/ListDeadLetterSourceQueuespagination options, none of which existed yet when upstream went quiet. - Refreshes
mix.exs/CI to current Elixir/OTP versions.
Installation
The library is published to Hex as beamlab_ex_aws_sqs because the original ex_aws_sqs package name is already taken on Hex.
def deps do
[
{:ex_aws, "~> 2.7"},
{:beamlab_ex_aws_sqs, github: "BeamLabEU/beamlab_ex_aws_sqs"},
# No Jason needed — Elixir >= 1.18 has built-in JSON support.
# Use `config :ex_aws, json_codec: JSON` (or keep Jason if preferred).
{:hackney, "~> 4.0"} # or any HTTP client ex_aws supports (only for tests here)
]
endOr once on Hex:
{:beamlab_ex_aws_sqs, "~> 4.0"}Note: The public API (module ExAws.SQS) and configuration (config :ex_aws, :sqs, ...) remain the same as the original. Only the dependency name in your mix.exs is prefixed.
Migrating from ex-aws/ex_aws_sqs
The public function names and options are unchanged — swapping the dependency source is enough to compile. What does change is the shape of a successful response, because there's no more XML-to-map parsing layer standing between you and AWS:
# before (ex-aws/ex_aws_sqs, XML/Query protocol)
{:ok, %{body: %{messages: [%{message_id: id, body: body} | _]}}} =
ExAws.SQS.receive_message(queue_url) |> ExAws.request()
# after (this fork, JSON protocol)
{:ok, %{"Messages" => [%{"MessageId" => id, "Body" => body} | _]}} =
ExAws.SQS.receive_message(queue_url) |> ExAws.request()In short: response bodies are now the raw JSON payload AWS returns, decoded by your configured
:json_codec (Elixir's built-in JSON module since 1.18, or e.g. Jason) — keyed exactly as the
AWS API Reference
documents for each action, with no snake_case/atom conversion. A couple of operations use
unusual casing straight from AWS (e.g. list_dead_letter_source_queues/1 returns a lowercase
"queueUrls" key) — that's an AWS quirk carried through as-is, not a bug here.
Binary message attribute values (if any) will appear base64-encoded in the raw responses.
You'll also want to drop :saxy and :sweet_xml from your deps if you added them for the old
parser, and can drop any config :ex_aws_sqs, parser: ... config — there's no parser to select
anymore.
send_message_batch/2
Each entry is a keyword list (or map) with at least :id and :message_body:
ExAws.SQS.send_message_batch(queue_url, [
[id: "a1", message_body: "payload1"],
[id: "a2", message_body: "payload2", delay_seconds: 10]
])
|> ExAws.request()
# {:ok, %{
# "Successful" => [%{"Id" => "a1", "MessageId" => "...", "MD5OfMessageBody" => "..."}, ...],
# "Failed" => []
# }}:id only needs to be unique within the batch — it's how you match each entry to its result in
"Successful"/"Failed".
Entries can be provided as keyword lists or maps.
Message attributes
When sending messages with :message_attributes, use maps (or a list of maps) with :name,
:data_type, and :value. Supported data types are :string, :number, and :binary.
For binary attributes, pass the raw binary as :value. The library automatically base64-encodes
it to satisfy the JSON protocol on the wire.
On receive, any binary message attributes in the response will contain base64-encoded strings
under "BinaryValue" (this is the raw form returned by AWS under the JSON protocol).
Example:
ExAws.SQS.send_message(queue_url, "body", message_attributes: [
%{name: "trace", data_type: :binary, value: <<1, 2, 3>>}
])Message move tasks (DLQ redrive)
These operations were added after the original library went quiet:
# Start moving messages from a DLQ back to the source (or another) queue
{:ok, %{"TaskHandle" => handle}} =
ExAws.SQS.start_message_move_task(dlq_arn) |> ExAws.request()
# Or with options
ExAws.SQS.start_message_move_task(dlq_arn,
destination_arn: target_arn,
max_number_of_messages_per_second: 100
)
# List recent tasks
ExAws.SQS.list_message_move_tasks(dlq_arn, max_results: 5) |> ExAws.request()
# Cancel if needed
ExAws.SQS.cancel_message_move_task(handle) |> ExAws.request()See the AWS docs linked from each function for details and limits.
Copyright and License
The MIT License (MIT)
Copyright (c) 2014 CargoSense, Inc. Copyright (c) 2026 BeamLab EU
See LICENSE for the full text.