Skip to content

Celery Alternatives in 2026: Dramatiq, FastStream, Taskiq, and Repid Compared

I ran into a wall with Celery last month. I had a service that needed to process webhook payloads — maybe a few thousand per minute, each making a couple of HTTP calls and writing results to Postgres. Nothing crazy. But the workers kept falling behind. More workers fixed it temporarily, but then the database connection pool got exhausted. I was throwing machines at a problem that felt like it should be a library choice issue.

Turns out, it was.

The benchmark that made me look twice

The author of Repid — one of the newer kids on the block — published a detailed benchmark comparison of five Python task queue libraries: Celery 5.6.3, Dramatiq 2.1.0, FastStream 0.6.7, Taskiq 0.12.4, and Repid 2.1.2. The results were stark.

For I/O-bound high-concurrency workloads, the async-native libraries (Repid, FastStream, Taskiq) were significantly faster than Celery. Not 10% faster. We’re talking orders of magnitude in some scenarios. For CPU-bound work, the gap nearly disappeared — once the CPU is saturated, the library overhead is a rounding error.

Here’s what the throughput looked like across different I/O task durations:

Throughput comparison (tasks/sec, higher is better)
Short tasks (1ms I/O):
Repid: 58,000
FastStream: 52,000
Taskiq: 45,000
Dramatiq: 12,000
Celery: 1,800
Medium tasks (10ms I/O):
Repid: 6,500
FastStream: 5,800
Taskiq: 5,200
Dramatiq: 2,100
Celery: 450

The gap at short task durations tells you everything. Celery’s per-task overhead — process forking, pickle serialization, AMQP protocol churn — dominates when the actual work is fast. Async-native libraries skip most of that overhead because they don’t need to spin up a new process or thread for every task.

What I learned about each library

Dramatiq — the simple sync switch

If you want to move away from Celery but keep a sync programming model, Dramatiq is the most straightforward path. It uses Redis or RabbitMQ, actors are just decorated functions, and it ships with a decent web UI out of the box.

dramatiq_example.py
import dramatiq
from dramatiq.brokers.redis import RedisBroker
dramatiq.set_broker(RedisBroker())
@dramatiq.actor(queue_name="send-email")
def send_email(user_id: int) -> None:
# no async needed
print(f"send email to {user_id}")

What surprised me: Dramatiq with gevent workers was significantly faster than Celery even though both are sync-first. Celery’s standard worker path has some rough edges — the benchmark author noted that running Celery required enabling a deprecated RabbitMQ feature (deprecated_features.permit.transient_nonexcl_queues = true). That’s not a great sign for a library that’s been around this long.

The tradeoff: no dependency injection, no async support, and fewer broker options. If your stack is simple and sync, Dramatiq is probably the right call.

Repid — fastest raw throughput

Repid was the fastest in every I/O benchmark, and it wasn’t close. It supports six brokers (RabbitMQ, Redis, NATS, SQS, GCP Pub/Sub, Kafka) — the widest coverage of any library in this comparison.

repid_example.py
from repid import Router, Connection
router = Router()
@router.actor(channel="send-email")
async def send_email(user_id: int) -> None:
print(f"send email to {user_id}")

I liked the per-actor ThreadPool/ProcessPool override — you can annotate individual actors to run in a thread pool or a process pool depending on whether they’re I/O-bound or CPU-bound. That’s something Celery makes painful (you end up with separate queues and separate worker processes).

Repid also has native AsyncAPI integration, which means you can generate API docs from your message definitions. Useful if your team treats the task queue as a first-class interface rather than an implementation detail.

The catch: it’s the newest project here. The author is upfront about their involvement. The ecosystem (plugins, extensions, community tutorials) is thinner than Celery’s.

FastStream — for stream-processing minds

FastStream approaches things differently. It treats message handling as stream processing rather than background jobs. If you’re coming from Kafka Streams or similar frameworks, this will click immediately.

faststream_example.py
from faststream import FastStream
from faststream.rabbit import RabbitBroker
from pydantic import BaseModel
broker = RabbitBroker()
class SendEmail(BaseModel):
user_id: int
@broker.subscriber("send-email")
async def send_email(message: SendEmail) -> None:
print(f"send email to {message.user_id}")

The Pydantic-native message validation is nice. The built-in dependency injection is genuinely useful for real services — you can inject DB sessions, HTTP clients, etc. without globals. And AsyncAPI support is native here too, since stream processing and API contracts go hand in hand.

The downside: the learning curve. The subscriber/publisher mental model is different from the task-queue model. And FastStream is heavier — if all you need is “run this function in the background”, it’s overkill.

Taskiq — the balanced async option

Taskiq sits between Repid and FastStream on the complexity scale. It’s async-first, supports result backends (Redis, Memcached), has a scheduler for periodic tasks, and supports dependency injection through extensions.

taskiq_example.py
from taskiq import TaskiqBroker
broker = TaskiqBroker()
@broker.task
async def send_email(user_id: int) -> None:
print(f"send email to {user_id}")

The scheduler feature is worth calling out. Many task queue use cases need periodic scheduling — Celery Beat covers this, but it’s a separate process. Taskiq has it built in to the worker.

What I didn’t love: the extension ecosystem is still growing. The DI extension works but feels bolted on. And broker support is narrower than Repid’s.

Where Celery still wins

Let me be fair. Celery has been the default since 2009. The documentation, while sprawling, covers almost everything. Stack Overflow answers exist for every edge case. The ecosystem of beat schedulers, result backends, monitoring tools (Flower), and integrations is unmatched.

If your team already knows Celery, and your throughput needs are modest, switching is a cost with no benefit. The day you start adding worker processes to compensate for per-task overhead, though, is the day you should start looking.

Production behavior matters more than benchmarks

Benchmarks tell you about throughput on a clean system. Real deployments face broker outages, deploys that need graceful shutdowns, and monitoring requirements.

This is where the differences get practical:

  • Broker outage handling: Repid and FastStream handle reconnection transparently in async workers. Celery workers can get into a zombie state if the broker goes down and comes back — the worker process is alive but not processing tasks. You need external monitoring (or Flower auto-reconnect, which doesn’t always work).

  • Graceful shutdown during deploys: With Celery’s --without-gossip --without-mingle --without-heartbeat flags, you can mostly get clean shutdowns. But the default settings cause workers to linger. Dramatiq handles this much better — tasks are rejected at the broker level when the worker is shutting down. Repid and Taskiq handle graceful stop as a first-class concern because the async event loop makes it natural.

  • Delayed scheduling: Celery requires a separate beat process for periodic tasks. Taskiq has scheduling built in. Repid uses a different approach — delayed tasks are stored in the broker itself, no separate scheduler needed.

  • Monitoring: Celery has Flower. Dramatiq ships a web UI. FastStream has AsyncAPI docs built in. Repid requires manual integration or your own monitoring. Taskiq has nothing built in — you log and monitor externally.

How to choose

This is the framework I’ve settled on for evaluating these libraries:

Start with your workload type. If most of your tasks are I/O-bound (HTTP calls, database queries, file uploads), async-native libraries give you dramatically better throughput per worker node. If you’re CPU-bound, pick by ecosystem fit — the library overhead doesn’t matter.

Decision matrix
┌─────────────────────────────────────────────────────┐
│ Workload Profile → Preferred Library │
├─────────────────────────────────────────────────────┤
│ I/O-bound, high concurrency → Repid or FastStream │
│ I/O-bound, moderate → Taskiq or Dramatiq │
│ CPU-bound → whichever ecosystem you prefer │
│ Need periodic scheduling → Taskiq (built-in) │
│ Stream processing mindset → FastStream │
│ Simplest Celery replacement → Dramatiq │
│ Maximum broker flexibility → Repid │
│ Ecosystem maturity is critical → Celery │
└─────────────────────────────────────────────────────┘

Then benchmark against your actual workload. Not a synthetic benchmark — your actual tasks, with your actual dependencies, on your actual infrastructure. The gap between libraries is workload-specific. A benchmark with artificial 1ms I/O tasks will exaggerate differences that might not matter for your 500ms database queries.

Consider your team’s mental model. FastStream is a genuinely better fit if your team thinks in event streams rather than job queues. That philosophical alignment saves more time than raw throughput ever will.

Plan for operational complexity. The smoothest deploy I’ve had was with Dramatiq — it handled SIGTERM during deploys correctly on the first try. Repid was close behind. Celery required reading three blog posts and tweaking six config flags.

What I’m doing now

I moved my webhook processing to Repid. The throughput improvement meant I could run half the worker processes. The graceful shutdown behavior meant deploy scripts stopped timing out. The actor-level pool override let me push CPU-intensive formatting tasks into a process pool while keeping the I/O tasks in the async event loop — all from the same worker process.

It took about two days to migrate. The API surface is small enough that the migration was mostly mechanical — redefine Celery tasks as Repid actors, adjust the startup scripts, update the deploy sequence.

Would I recommend everyone drop Celery? No. If your system handles its load fine and your team is productive, don’t fix what isn’t broken. But if you’re adding workers to keep up, or if you’re frustrated with Celery’s operational quirks, the alternatives in 2026 are real. I wish I’d benchmarked earlier — it would’ve saved me a lot of machines.

Final Words + More Resources

My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me

Here are also the most important links from this article along with some further resources that will help you in this scope:

Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!

Comments