Django 6.0 Is Out - Security, Ergonomics, and Finally Built-In Features
Django 6.0 landed on December 3, 2025.
And honestly? This one feels like a love letter to the kinds of things Django devs care about: fewer footguns, cleaner patterns, and more “you shouldn’t need a third-party app for that.”
Below are the changes that matter most for software developers shipping real apps.
The big headline features
1. Built-in Content Security Policy (CSP) support
Django now ships first-class CSP tooling: middleware to add headers, nonce support, and settings that let you define policies in a structured way.
What I like here is the “Django-ness” of it: you’re not hand-rolling response headers everywhere; you get a coherent framework-level approach.
Pieces to know:
ContentSecurityPolicyMiddlewarecsp()context processor (nonce support)SECURE_CSPandSECURE_CSP_REPORT_ONLYsettings
2. Template Partials (a clean, built-in way to do reusable fragments)
Django templates now support template partials via {% partialdef %} and {% partial %}.
You can also reference partials using a template_name#partial_name syntax in template loading and inclusion flows.
If you’ve ever ended up with a graveyard of tiny {% include %} files just to reuse a button + icon snippet… this is a big quality-of-life win.
3. Background Tasks: a built-in task framework (without pretending to be Celery)
Django 6 introduces a Tasks framework for running work outside the request/response cycle: define tasks, validate args, enqueue, store results—while still leaving actual execution to external workers/infrastructure.
Key detail (and it’s important): Django helps you create and queue tasks, but does not ship a worker. You run workers however you want (a separate process, a service, a platform primitive).
Configuration happens via the TASKS setting, and the built-in backends are mainly for dev/testing.
4. Email is modernized under the hood (Python’s modern email API)
Email handling now uses Python’s modern email API centered around email.message.EmailMessage.
Notably, EmailMessage.message() now returns an instance of Python’s EmailMessage (and Django’s old “SafeMIME…” types are on the way out).
This is one of those changes you won’t celebrate until you touch encoding / Unicode / multipart edge cases… and then you’ll be very glad it’s cleaner.
Smaller features that you’ll feel day-to-day
A bunch of “little” improvements add up in 6.0:
- Admin polish: updated Font Awesome icon set, more customizable password-change form, and clearer styling for message levels.
- Auth: PBKDF2 default iterations increased (stronger password hashing by default).
- Postgres: a new
Lexemeexpression for full-text search control, plus better checks and router hints for extension operations. - Staticfiles: more reproducible manifests + less noisy collectstatic at verbosity 1.
- Migrations: can serialize
zoneinfo.ZoneInfo, can re-squash squashed migrations, and better serialization for weird kwargs. - Models/ORM: ordering support for aggregates, a generally available
StringAgg, a specificModel.NotUpdatedexception when forced updates hit zero rows, betterCompositePrimaryKeysupport, and more. - Pagination:
AsyncPaginator/AsyncPage. - Templates:
forloop.length, plus querystring fixes and expanded args support. - Tests:
DiscoverRunnersupports parallel execution under the forkserver start method.
This is the stuff that doesn’t make a flashy keynote slide… but makes you smile six months from now.
Compatibility and “read this before upgrading”
Python & DB support changes
- Django 6.0 supports Python 3.12, 3.13, 3.14. Django 5.2.x is the last to support Python 3.10/3.11.
- MariaDB 10.5 is dropped; Django 6.0 supports 10.6+.
Backwards-incompatible changes that can bite
DEFAULT_AUTO_FIELDnow defaults toBigAutoField, and the “explicit defaults” were removed from project/app templates.- Custom ORM expressions / lookups:
as_sql()should return params as a tuple, not list-or-tuple. - Email internals changed; anything relying on undocumented underscored methods needs review.
- Third-party DB backend API changes (notably around RETURNING methods and column dropping behavior).
Deprecations and removals worth scanning for
- Django is tightening “positional args for less common parameters” in
django.core.mailAPIs (deprecation warnings now). - A pile of old deprecations are now gone (including cx_Oracle support removed, URLField default scheme now “https”, and more).
My “Django 6.0 upgrade” checklist (fast but realistic)
- Upgrade Python first (aim for 3.12+), then bump Django.
- Run your test suite with warnings visible (Django explicitly recommends watching deprecations closely).
- Grep your codebase for:
- custom ORM expressions (
as_sql) - forced updates and anything catching generic
DatabaseError - mail sending and custom email subclasses
- anything depending on removed APIs (especially older DB / prefetch internals)
- custom ORM expressions (
- If you’re on MariaDB, confirm you’re 10.6+.
- If you didn’t explicitly set
DEFAULT_AUTO_FIELD, check whether migrations or PK assumptions change in your project.
The vibe of Django 6.0
The best Django releases don’t just add features — they reduce the number of decisions you have to keep re-making across projects.
- Security gets more structured (CSP).
- Templates get more composable (partials).
- Background work gets more standard (tasks framework).
- Email gets more sane (modern API).
Django 6.0 is about making the framework feel less like “a collection of tools” and more like “a coherent platform where the common patterns are built-in and the sharp edges are sanded down.”
If you’re shipping Django apps in production, this release gives you less to worry about and more to work with. That’s the kind of upgrade that matters.