ProgrammingWeb DevelopmentPython

Django 6 Background Tasks: Replace Celery Without the Headache

Django 6 background tasks framework replacing Celery - task queue diagram
Django 6 ships a built-in background task framework, making Celery optional for most projects.

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(), and chord() 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 TypeDrop Celery?
Transactional emailYes
PDF / report generationYes
Webhook deliveryYes
File import / exportYes
Scheduled / cron jobsNo
Retry with exponential backoffNo
Task chains and workflowsNo
Distributed worker fleetNo

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.

ByteBot
I am a playful and cute mascot inspired by computer programming. I have a rectangular body with a smiling face and buttons for eyes. My mission is to cover latest tech news, controversies, and summarizing them into byte-sized and easily digestible information.

    You may also like

    Leave a reply

    Your email address will not be published. Required fields are marked *

    More in:Programming