Celery vs RQ vs Dramatiq: Python Task Queues Compared

Celery, RQ and Dramatiq all run Python code in background workers. Compare brokers, scheduling, retries and setup effort, and pick the right one.

Celery, RQ and Dramatiq all do the same basic job: run a Python function in a separate worker process so your web request doesn’t have to wait for it. They differ in how much they do for you and how much setup they ask for. RQ is the simplest and needs Redis. Dramatiq is a reliable middle ground. Celery is the most complete and the most work to run.

At a glance

CeleryRQDramatiq
BrokersRabbitMQ, Redis, Amazon SQS and othersRedis or Valkey onlyRabbitMQ or Redis
RetriesYes, configurable per taskBuilt inAutomatic, with exponential backoff
Scheduled and repeating jobsCelery BeatBuilt in (enqueue_in, enqueue_at, repeats, cron-style)Delayed messages built in; recurring jobs via APScheduler
WindowsNot supported (per its docs)Needs WSL or SimpleWorkerNot stated in its docs
Setup effortHighestLowestMedium

Details in the table come from each project’s own documentation. If you want the background on how task queues work at all, read What Is Celery? first.

RQ: the simple one

RQ describes itself as a simple library for queueing jobs and processing them in the background with workers, backed by Redis or Valkey. There is almost nothing to learn: any ordinary function is a job.

from redis import Redis
from rq import Queue

queue = Queue(connection=Redis())
job = queue.enqueue(count_words_at_url, "https://example.com")

Then you start a worker with rq worker. Priorities come from using several queues (rq worker high low serves the high queue first). Scheduling is built in, so you can queue a job for later with enqueue_in() or enqueue_at() and run workers with rq worker --with-scheduler.

Choose RQ when you already run Redis, your jobs are straightforward, and you want to be productive in an afternoon. The limits to know: Redis or Valkey is the only backend, and its workers use fork(), so Windows needs WSL.

Dramatiq: reliable by default

Dramatiq calls itself a fast and reliable distributed task processing library. You turn a function into an actor with a decorator and send it a message:

import dramatiq

@dramatiq.actor
def count_words(url):
    ...

count_words.send("https://example.com")

Workers are started with the dramatiq command. The reliability features are the selling point. A message that raises an exception is automatically retried with exponential backoff, and one that keeps failing goes to a dead-letter queue where, on the RabbitMQ broker, it is kept for up to a week by default. You can also set time limits and age limits per actor.

Two things to know. It uses RabbitMQ by default, so for Redis you configure the broker. And it has no cron-style scheduler of its own: the cookbook recommends pairing it with APScheduler. Async functions are supported once you enable the AsyncIO middleware. Dramatiq is LGPL-licensed, which matters to some companies.

Celery: the full toolkit

Celery is the long-standing default. It supports RabbitMQ, Redis and Amazon SQS as stable brokers, with more experimental ones, and it comes with Celery Beat for periodic tasks, a large ecosystem and a lot of documentation. That breadth is also its cost: more configuration, more moving parts, and more to understand when something goes wrong.

Choose Celery when you need its breadth: SQS as a broker, complex task workflows, or an established ecosystem and examples for your framework. If you are on Django, it is the option you will find the most guides for.

How to choose

  • Small to medium app, already have Redis, want minimum setup: RQ.
  • Want retries, time limits and dead-letter handling working without extra configuration: Dramatiq.
  • Need many broker options, heavy scheduling, or complex workflows, or you’re on a large Django project: Celery.
  • Just a few quick background jobs in a FastAPI app: you may not need any of them yet. Use the framework’s built-in background tasks until jobs have to survive restarts or run on other machines.

Whichever you pick, the worker is a separate process you have to deploy, monitor and restart. Budget for that before choosing the most powerful option.

Frequently Asked Questions

What is the difference between Celery, RQ and Dramatiq?

All three run Python functions in background worker processes. Celery is the most featureful and supports the most brokers (RabbitMQ, Redis, Amazon SQS and more) but is the most complex to set up. RQ is the simplest and only works with Redis or Valkey. Dramatiq sits in between: it supports RabbitMQ and Redis, with automatic retries and time limits built in.

Which Python task queue is easiest to set up?

RQ. You need a Redis or Valkey server, then you queue any plain Python function with queue.enqueue() and start a worker with rq worker. Celery and Dramatiq both need more configuration, and Dramatiq’s default broker is RabbitMQ unless you configure Redis.

Does RQ work on Windows?

Not out of the box. RQ’s documentation says its workers rely on fork(), so on Windows you need the Windows Subsystem for Linux, or you can use its SimpleWorker. Celery’s documentation also says it doesn’t support Windows.

Can Dramatiq run scheduled or periodic jobs?

It can delay a message to run later, and its cookbook recommends APScheduler for recurring jobs, with a cron trigger that sends messages on a schedule. Celery has Celery Beat and RQ has built-in scheduling, including repeating jobs.

Do I need a task queue at all?

Not always. For occasional, non-critical background work in a small app, a framework’s built-in background task feature such as FastAPI’s BackgroundTasks is usually enough. A task queue becomes worth it when jobs must survive a restart, be retried, run on separate machines, or be scheduled.