Hey everyone! Django 6.0 is finally on the horizon (expected December 2025), and I’ve been diving deep into the release notes so you don’t have to. And trust me — this isn’t just another routine version bump. The Django team has truly outdone themselves this time with powerful new features, major improvements, and some exciting changes that will shape how we build modern web apps.
The Big Stuff That Actually Matters
Background Tasks – Finally!
Okay, can we talk about how long we’ve been waiting for this? Django now has a built-in tasks framework. No more immediately reaching for Celery or RQ the moment you need to send an email in the background.
Here’s how simple it is:
from django.core.mail import send_mail
from django.tasks import task
@task
def email_users(emails, subject, message):
return send_mail(subject, message, None, emails)
# Then just enqueue it
email_users.enqueue(
emails=["user@example.com"],
subject="You have a message",
message="Hello there!",
)
Now, before you get too excited – Django handles the queueing part, but you still need to manage your own workers. Think of it as Django giving you the tools, but you bring the infrastructure. It’s a great foundation, though, and the built-in backends are perfect for development.
Content Security Policy Support
Remember when implementing CSP felt like writing a master’s thesis? Not anymore. Django 6.0 has built-in CSP support that actually makes sense.
from django.utils.csp import CSP
SECURE_CSP = {
"default-src": [CSP.SELF],
"script-src": [CSP.SELF, CSP.NONCE],
"img-src": [CSP.SELF, "https:"],
}
That’s it. No third-party packages, no hair-pulling. Just clean, Pythonic configuration. The middleware handles everything, including automatic nonce generation for your scripts.
Template Partials
This one’s for everyone who’s been using {% include %} tags and feeling like there should be a better way. Template partials let you define reusable fragments right in your template:
{% partialdef header %}
<h1>{{ title }}</h1>
<p>{{ subtitle }}</p>
{% endpartialdef %}
{% partial header title="Welcome" subtitle="Good to see you" %}
You can even reference them from other templates using template_name#partial_name syntax. It’s like components, but without the overhead. If you’ve been using django-template-partials, there’s a migration guide to help you switch over.
The Python 3.12+ Move
Here’s the thing – Django 6.0 drops support for Python 3.10 and 3.11. I know, I know, upgrading Python versions is always a pain. But honestly? Python 3.12 brought some solid performance improvements, and this is probably the push you needed anyway.
If you’re still on 3.10 or 3.11, stick with Django 5.2 until you’re ready to upgrade. It’s LTS and will be supported until April 2026.
The Little Things That’ll Make Your Day
Modern Email API
Django finally moved to Python’s modern email API. If you’ve ever had to deal with email encoding issues (and who hasn’t?), you’ll appreciate this. Everything’s cleaner, more Unicode-friendly, and just… works better.
Better Pagination for Async
AsyncPaginator and AsyncPage are here. If you’re building async views, you no longer have to wrap your pagination in sync_to_async. It’s the little things, you know?
Template Improvements
forloop.lengthis now available in for loops (why wasn’t this always there?)- The
querystringtag consistently prefixes with?now - Multiple positional arguments are supported in
querystringtag
Admin Upgrades
Font Awesome 6.7.2 icons across the admin interface. Subtle, but it looks sharp. Also, you can now customize the password change form with AdminSite.password_change_form.
The Stuff That Might Break Things
Look, I’m not going to sugarcoat it. There are some breaking changes:
- DEFAULT_AUTO_FIELD now defaults to
BigAutoFieldinstead ofAutoField. Most projects created after Django 3.2 won’t notice, but if you’ve been ignoring that warning, now’s the time to deal with it. - Email changes – if you have custom email subclasses that mess with internal methods, check them. The internal implementation changed significantly.
- MariaDB 10.5 support has been dropped. Upgrade to 10.6+ if you haven’t already.
- Custom ORM expressions need to return params as tuples now, not lists.
Should You Upgrade?
If you’re on Django 5.2 and already using Python 3.12+? Absolutely. The new features are worth it, and the upgrade path is pretty smooth.
If you’re on an older version? Maybe wait for 6.0.1 or 6.0.2. Let the early adopters find the edge cases first. There’s no shame in that – it’s just smart.
If you’re on the 4.2 LTS? You’ve got until April 2026, so no rush. But start planning your upgrade path now.
The Bottom Line
Django 6.0 feels like the framework is maturing in all the right ways. Built-in background tasks, proper CSP support, template partials – these are things the community has been solving with third-party packages for years. Bringing them into the core just makes sense.
Is it revolutionary? No. Is it solid, practical, and exactly what Django needed? Absolutely.
The release is expected in December 2025, with the beta already available. If you want to help test it (and you should), grab the release candidate and give it a spin in a non-production environment.
What are you most excited about? Let me know in the comments. I’m personally thrilled about the tasks framework – goodbye Celery boilerplate!
Update: Make sure to check the full release notes for all the details, deprecations, and migration guides. There’s way more than I could cover here.

