ExAws.SQS

Hex.pmHex DocsLicense

Service 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:

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)
]
end

Or 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.

The MIT License (MIT)

Copyright (c) 2014 CargoSense, Inc. Copyright (c) 2026 BeamLab EU

See LICENSE for the full text.