Django tasks in your database
Stop running Redis to send an email. Queue work in your existing database, where a dead worker doesn't mean lost tasks.
Open source
BSD 3-Clause
pip install django-ox
with transaction.atomic():
order = Order.objects.create(...)
send_confirmation.enqueue(order.pk)
Both rows commit, or neither does.
2,000 of 2,000
Tasks finished after 20 worker kills per trial (django-ox 1.3.0)
up to 1.7×
The throughput of django-tasks-db, 100,000 tasks, 16 workers, same connection settings
0.71 s
To enqueue 10,000 tasks (django-ox 1.3.0)
New in django-ox 1.9.0
Everything is free and open source.
Unique tasks, batches, rate limiting and workflows are now included in django-ox under BSD 3-Clause. These four features require Django 6.0+.
A stable core public API since 1.0.0.
20 releases. Core public API stable since 1.0.0 (September 2026). The workflow API is provisional.
6,936 test cases in the 1.9.1 suite.
Featured in PyCoder's Weekly #752 (). Listed in awesome-django under Task Queues.
Run fewer services
Keep the queue in your database
Tasks are rows you can inspect in Django admin. Run a dedicated worker without adding Redis or RabbitMQ.
Back to the queue
Recover a stopped worker's tasks
Unfinished tasks return to the queue when a worker dies. You don't need a separate recovery script.
one COMMIT
Commit tasks with your data
Create an order and enqueue its confirmation inside transaction.atomic(). A rollback leaves neither row behind.
Compare the workers
100,000 tasks: about 30 seconds for django-ox, about 50 for django-tasks-db
With 16 workers and persistent connections, django-ox drained 100,000 tasks in about 30 seconds. django-tasks-db took about 50 seconds. Tasks per second, higher is better.
Both bars use a 0 to 4,000 tasks/s scale. Matched settings, health checks off, 16 workers.
PostgreSQL 16; no-op tasks; django-ox 1.9.0 vs django-tasks-db 0.13.0; medians of five runs.
Methodology and resultsdjango-ox
One project. All features included.
Free and open source under BSD 3-Clause.
Run tasks in your database
- Database-backed Django Tasks worker
- Retries and dead-worker recovery
- Recurring schedules
- Django admin integration
- Health checks and bulk enqueue
Coordinate your work
These four features require Django 6.0+.
What is django-ox?
A database-backed worker for Django's Tasks framework. Tasks live in database rows. django-ox includes retries, worker recovery, recurring schedules, unique tasks, batches, rate limiting and workflows.
Do I need Redis or RabbitMQ?
No. django-ox uses your existing database. You still run a worker process to execute tasks.
What happens if a worker stops mid-task?
Its unfinished task returns to the queue and may run again. Make tasks tolerate repeated execution. External side effects aren't exactly-once.
Can I enqueue a task inside a database transaction?
Yes. Put the database write and enqueue() inside the same transaction.atomic() block. Both rows must use the same database. They commit or roll back together.
Are all features included?
Yes. All features are free and open source under BSD 3-Clause. Unique tasks, batches, rate limiting and workflows are included in django-ox 1.9.0. These four features require Django 6.0+. See the feature overview.
What should I install?
For a new installation, run pip install django-ox. Follow the getting started guide to configure Django and run a worker.
The oxpull 1.9.1 package on PyPI is a metapackage. It depends on django-ox>=1.9.1 and contains no Python module. django-ox supplies the oxpull module.
How do I upgrade an earlier oxpull install?
Follow the tested upgrade procedure. Stop workers and back up the database first. Uninstall the earlier oxpull distribution before installing django-ox 1.9.0.
Do not uninstall an earlier oxpull distribution after installing django-ox 1.9.0 unless you then repair the shared files as described below. This warning does not apply to the oxpull 1.9.0 metapackage: uninstalling it leaves django-ox's files in place.
If you already ran pip install -U oxpull, or installed django-ox over an earlier oxpull distribution, keep workers stopped while repairing the overlapping install. Run pip uninstall oxpull, then pip install --force-reinstall --no-deps django-ox, then pip check. Resolve any errors reported by pip check, then restart workers.