
Django 6.0 ships a built-in background task framework — no Redis broker, no Celery installation, no second process to manage in your Procfile. For the first time in Django’s history, you can defer work to the background without bolting on external infrastructure. That changes the calculation for most projects. Not all of them, but most.
What Changed in Django 6
The new django.tasks module gives you a @task decorator, a queue store (database-backed by default), and a worker management command. The Django 6.0 release notes are explicit: this is not a Celery replacement. It is a framework — a contract for how tasks are defined, enqueued, and tracked. Think of it as the standard interface your code talks to, with pluggable backends handling actual execution.
For most applications, the database backend is the right choice to start. Your task queue lives in your existing database. No new services, no new credentials to rotate. The official Django Tasks documentation covers all available backends, including how to build a custom one.
Setup: Three Changes to settings.py
INSTALLED_APPS = [
...
'django_tasks',
'django_tasks.backends.database',
]
TASKS = {
"default": {
"BACKEND": "django_tasks.backends.database.DatabaseBackend"
}
}
Run migrations to create the task tables, then start the worker:
python manage.py migrate
python manage.py db_worker
The Migration Is Two Line Changes
Here is what a typical Celery task looks like before:
# tasks.py — Celery
from celery import shared_task
@shared_task
def send_welcome_email(user_id):
user = User.objects.get(pk=user_id)
send_email(user.email, "Welcome to the app!")
# views.py
send_welcome_email.delay(user_id=request.user.pk)
And after, with Django 6:
# tasks.py — Django 6
from django.tasks import task
@task
def send_welcome_email(user_id):
user = User.objects.get(pk=user_id)
send_email(user.email, "Welcome to the app!")
# views.py
send_welcome_email.enqueue(user_id=request.user.pk)
@shared_task becomes @task. .delay() becomes .enqueue(). Remove your CELERY_* settings and the celery -A myapp worker startup command. That is the full migration for a fire-and-forget task.
Where Django Tasks Wins
The framework handles the 80% case cleanly. If your background work looks like any of the following, you can drop Celery today:
- Welcome and transactional emails
- Password reset processing
- PDF and report generation
- Webhook delivery
- Cache warming after data changes
- File imports and exports
- Search index updates
The infrastructure win is real. A staging environment that previously needed Django + Redis + Celery worker + Flower now needs Django + db_worker. That is one fewer service to provision, monitor, and rotate secrets for. On Heroku, Railway, or Render, it is one fewer dyno or service in your config.
Where Celery Still Wins
Django Tasks does not yet ship with a scheduler, retry semantics, or workflow primitives. If your tasks rely on any of the following, Celery is still the right tool:
- Periodic tasks / cron: Celery Beat has no equivalent in Django Tasks. Third-party add-ons exist but are early-stage.
- Automatic retry with backoff:
self.retry(countdown=60)is not available. Failed tasks stay failed. - Workflow chains and groups:
chain(),group(), andchord()have no analog. - Monitoring: Flower gives you per-task visibility, worker health, and queue depth at a glance. The Django admin shows task rows but is not a monitoring tool.
- Distributed workers at scale: If you are running workers across multiple machines handling tens of thousands of tasks per day, Celery with Redis is still the right architecture.
The Decision Table
| Task Type | Drop Celery? |
|---|---|
| Transactional email | Yes |
| PDF / report generation | Yes |
| Webhook delivery | Yes |
| File import / export | Yes |
| Scheduled / cron jobs | No |
| Retry with exponential backoff | No |
| Task chains and workflows | No |
| Distributed worker fleet | No |
The Verdict
For any project where the background work is “run this function, don’t block the request” — Django 6 Tasks is the right default. MVPs, internal tools, and most SaaS apps under moderate load can drop Celery immediately. The migration takes less time than it took to write this post.
If you are running Celery Beat for scheduled jobs or you have tasks that must retry on failure, keep Celery for those specific use cases. You can run Django Tasks alongside Celery during a migration — they are not mutually exclusive.
Django 6.2, currently in development, has early hints at adding retry support and a lightweight scheduler. The story will get better. For now, Adam Johnson’s rundown of Django 6.0 is the best starting point for evaluating the full upgrade scope alongside background tasks.
One less broker to manage is a real win. Ship the simplest thing that works.













