akira/exq: a Resque and Sidekiq compatible job queue for Elixir, and the case for not adding one
Job processing library for Elixir - compatible with Resque / Sidekiq
At a glance
- What is it?
- Exq puts background job processing on Redis for Elixir applications while staying compatible with the Resque and Sidekiq wire format, which means the Sidekiq UI can read its stats. The project itself argues you may not need it at all, since OTP already ships the primitives.
- Who is it for?
- Adopt exq when your Elixir application already talks to Redis, needs jobs to survive node restarts, and wants the Sidekiq stats format so existing dashboards keep working, and when you accept a Redis dependency plus the serialization overhead that comes with it. Do not adopt it for short in-process work that GenServer, Task or GenStage already covers, because the project is explicit that a Redis backed queue adds infrastructure and marshalling cost for that case.
- Can I use it commercially?
- Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
- Is it still maintained?
- Yes. The repository last received commits 15 days ago.
- What is it written in?
- Mainly Elixir, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 21, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The README opens by arguing against its own library
Most library documentation opens with what the library does. This one opens with a warning. Before recommending Exq, the project asks you to get familiar with OTP and see whether that is already enough, because Elixir and the BEAM provide several primitives for background work out of the box. The named alternatives are GenServer, Task, GenStage and Supervisor, with links to each.
That advice is not decoration. The stated reason to hesitate is that a Redis backed queue adds infrastructure complexity, and adds overhead from serialization and marshalling of every job payload. Exq is presented as the right answer for a narrower case: jobs that need to be durable, retries with exponential backoff, and jobs scheduled for the future, all of which must survive application restarts.
So the audience is a team that has already decided a plain in-process task is not enough, and that accepts a Redis instance as part of the deployment. It is not a default to reach for.
The repository is an Elixir project with the usual shape: `lib/`, `config/`, `test/`, a `bench/` directory, `mix.exs` and `mix.lock`. The last push was on 2026-10-08, and the most recent release, v0.25.0, was published on the same day, with v0.24.0 dated 2026-07-27 and v0.23.0 dated 2025-11-04.
Redis holds the jobs, and the format is deliberately Sidekiq's
Exq uses Redis as the store for background processing jobs, and it goes out of its way to speak a format that Resque and Sidekiq already understand. The stated payoff is integration rather than isolation: an existing Rails or Django application that already enqueues Resque compatible background jobs can point at Exq with little or no change, and you can run Exq and Toniq in the same application for different workers.
Compatibility extends to observability. Because Exq writes the Sidekiq stats format, you can use the Sidekiq UI to view job statuses rather than maintaining a separate dashboard. The library tracks several statistics, including failed, busy and processed jobs.
Job durability is handled with a specific Redis command. Exq stores in progress jobs in a backup queue using Redis RPOPLPUSH, so if the system or worker restarts while a job is in progress, that job is re-enqueued when the node comes back instead of being lost. Retries are supported with exponential backoff, and the backoff strategy is not fixed: the `backoff` option can be pointed at your own module that implements `Exq.Backoff.Behaviour` to change the default behaviour, which by default scales exponentially on the job's `retry_count`.
Installing Exq means adding a dependency and running Redis
The install path is short. Exq assumes a Redis instance already exists. The project's suggestion for macOS is Homebrew, then a local server process:
> brew install redis> redis-serverThe library itself is added to your `mix.exs` dependencies, and the version shown is the one matching the current release:
defp deps do
[
# ... other deps
{:exq, "~> 0.25.0"}
]
endAfter that, `mix deps.get` pulls the package. The project also points to a screencast on elixircasts.io for people who prefer video instructions on installing and using the library.
One licensing detail deserves a flag before you go further. The repository is listed under a custom licence that GitHub cannot classify, and the project points readers at the LICENSE file. What those terms permit for commercial use, redistribution or modification is something you have to read in that file yourself, and no summary here substitutes for it.
Configuration keys that decide how the workers behave
Exq reads its configuration from your config.exs file. The Redis connection can be expressed as separate keys for host, port, password and namespace, where the namespace isolates Exq data inside a shared Redis, or as a single URL through the `url` config key, in which case the other Redis options are not needed. Options can also be written in the `{:system, "VARNAME"}` format so a value is resolved from the runtime environment, which is what you want for a password in a deployed environment.
The documented configuration block shows the shape of the whole surface:
config :exq,
name: Exq,
host: "127.0.0.1",
port: 6379,
password: "optional_redis_auth",
namespace: "exq",
concurrency: :infinite,
queues: ["default"],
poll_timeout: 50,
scheduler_poll_timeout: 200,
scheduler_enable: true,
max_retries: 25,
mode: :default,
shutdown_timeout: 5000Several of these carry behaviour worth understanding. `queues` lists the queues Exq listens to. `concurrency` sets how many jobs run at once and can be set to `:infinite` to remove throttling entirely, or to a number per queue. `max_retries` bounds the retry attempts, and `scheduler_enable` with its own poll timeout governs the scheduler that handles jobs scheduled for the future. `shutdown_timeout` is the number of milliseconds to wait for in flight jobs when the application shuts down, defaulting to 5000 ms, and shutdown attempts to let workers terminate gracefully. The `name` option changes Exq's registered name, the equivalent of calling `Exq.start_link([name: Name])`.
mode lets you enqueue on one node and process on another
The `mode` option controls which components of Exq are started, and the design intent is explicit: it exists for the case where you want to only enqueue jobs in one node and run the workers on different nodes. The available values are `:default`, which starts worker, enqueuer and API, `:enqueuer`, which starts only the enqueuer, `:api`, which starts only the API, and `[:api, :enqueuer]`, which starts both without the worker.
`start_on_application` gives you a related lever. If it is set to `false`, Exq does not start automatically when your application boots, and you start it yourself with `Exq.start_link/1`.
This separation is the part of Exq that is genuinely specific to Elixir rather than borrowed from the Ruby ecosystem, because it maps onto how BEAM applications are supervised and partitioned. A multi node deployment can point several Erlang nodes at one Redis pool, which the project lists as a feature, and the mode option is what lets an enqueue only node avoid pulling in worker capacity it will never use.
Per queue concurrency, and a documentation gap in the example
Concurrency is the setting most teams will fight with, and Exq supports it per queue. You can apply the same `concurrency` option to every queue:
config :exq,
host: "127.0.0.1",
port: 6379,
namespace: "exq",
concurrency: 1000,
queues: ["default"]The project also says you can specify concurrency on a per queue basis, and the text gives an example where one queue runs at 10_000 and another at 10.
The wider shape of the design is that Exq will run an uncapped number of jobs or apply a maximum limit per queue, and that there is no time limit on how long a single job may run. That combination is deliberate: an unbounded job duration plus a bounded concurrency is a reasonable model for long running work, but it means the queue is only as well behaved as the code inside the job.
What Exq costs you next to plain OTP
The cost picture is stated plainly enough that it is worth repeating in specific terms. Every job payload crossing the Redis boundary is serialized and marshalled, and the queue itself lives in Redis rather than in memory inside your application. You also take on a Redis instance as infrastructure, and a `namespace` becomes a boundary you have to manage if several applications share one server.
The failure modes are specific as well. A worker that dies mid job leaves the entry in the backup queue, and recovery happens when the node restarts. A job that keeps failing is retried up to `max_retries` times with exponential backoff, after which it is counted as failed. Whether failed jobs are inspected by hand through the Sidekiq UI or by some other means is a decision the project leaves open.
The alternative is not another library but another approach: build the queue inside your own application with GenServer, Task, GenStage and Supervisor, which the project recommends you consider first. The difference in approach is where durability lives. OTP gives you supervision and recovery within one node, while Exq moves the queue to Redis so jobs survive node restarts and can be shared across several Erlang nodes at the cost of serialization and a second piece of infrastructure.
Editorial conclusion
Adopt exq when your Elixir application already talks to Redis, needs jobs to survive node restarts, and wants the Sidekiq stats format so existing dashboards keep working, and when you accept a Redis dependency plus the serialization overhead that comes with it. Do not adopt it for short in-process work that GenServer, Task or GenStage already covers, because the project is explicit that a Redis backed queue adds infrastructure and marshalling cost for that case. Verify first that the custom LICENSE file grants your organisation the rights you need, since GitHub could not classify it, and confirm your Redis version supports the RPOPLPUSH behaviour Exq relies on for its in progress backup queue.
Frequently asked questions
How do I install exq in an Elixir project?
Add the dependency to your mix.exs as `{:exq, "~> 0.25.0"}` and run `mix deps.get`. Exq also expects a Redis instance to be available, for example installed with `brew install redis` and started with `redis-server`.
Can I see exq jobs in the Sidekiq UI?
Yes. Exq uses a format that is Resque and Sidekiq compatible, and it is compatible with the Sidekiq stats format, so the Sidekiq UI can be used to view job statuses alongside the statistics Exq tracks such as failed, busy and processed jobs.
What happens to a job that is still running when the node restarts?
Exq stores in progress jobs in a backup queue using the Redis RPOPLPUSH command, so a job interrupted by a system or worker restart is re-enqueued when the node restarts rather than being lost.
How do I run only the enqueuer on one node and the workers on another?
Set the `mode` option to `:enqueuer` on the node that should only enqueue, and leave `mode: :default` on the nodes that should also run workers. The available modes are `:default`, `:enqueuer`, `:api` and `[:api, :enqueuer]`.
Can exq retry failed jobs with exponential backoff?
Yes. Retries with exponential backoff are supported, scaling on the job's retry_count by default, and `max_retries` sets the limit. The `backoff` option can be set to a module implementing `Exq.Backoff.Behaviour` to replace the default strategy.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/akira-exq)Was this useful?