Django 6.1 shipped on August 5, 2026, according to the release announcement, and it starts a clock for anyone still running 6.0. Django 6.0 exited mainstream support the same day. It now gets security and data-loss fixes only, and that window closes in April 2027, per Django's published support timeline. After that date, Django 6.0 gets nothing at all, not even a fix for a critical vulnerability.
Django 6.1 shipped August 5, 2026, what changes for teams on 6.0
Django 6.0's final bugfix release, 6.0.8, went out on August 4, 2026, one day ahead of 6.1. From here, 6.0 moves into the part of Django's release cycle reserved for security and data-loss fixes, and nothing else. New bugs that aren't security issues won't get backported. If your team files an issue against 6.0 today, expect "upgrade to 6.1" as the answer for anything short of a CVE.
The April 2027 deadline
Django 6.0 keeps receiving security and data-loss patches until April 2027, then it's end of life. No patches, security or otherwise, after that date. This is Django's own stated support-lifecycle policy, not a contract or a guarantee backed by any external body, so treat April 2027 as a planning deadline rather than a promise with legal teeth. If your compliance process needs a supported framework version on record, 6.0 stops qualifying the day that window closes.
The version floors that will block an upgrade
Before pip install django==6.1 does anything useful, your infrastructure has to clear four new floors set out in Django's release notes on the new version floors. These aren't soft recommendations. Django 6.1 won't run below them.
| Dependency | Minimum version for Django 6.1 |
|---|---|
| Python | 3.12, 3.13, or 3.14, latest patch of each series only |
| PostgreSQL | 15 and higher |
| MySQL | 8.4 and higher |
| MariaDB | 10.11 and higher |
| SQLite | 3.37.0 and higher, up from 3.31.0 |
The SQLite jump catches teams off guard most often, because it's easy to forget SQLite has a version at all until a CI runner ships an old one. Check your base Docker image before you check your code.
What breaks in existing code
Three changes in Django 6.1 will pass code review and then fail in production or CI if nobody's looking for them.
1. first() and last() stop ordering by primary key when ordering was explicitly cleared
If you called order_by() with no arguments to clear a queryset's default ordering, first() and last() used to fall back to ordering by primary key anyway. Django 6.1 drops that fallback, one of three backwards-incompatible query changes flagged in the release notes: you get whatever order the database returns, which can change between queries. If you rely on that fallback, add explicit ordering back.
2. Combined querysets now raise DatabaseError on unselected ordering fields
union(), difference(), and intersection() now apply the model's default Options.ordering to the combined result. If that ordering field isn't selected through values() or values_list(), the combined query raises DatabaseError instead of silently ignoring the problem. That's a CI failure instead of a silent bug, but it still stops a deploy if you haven't tested combined querysets. Call order_by() with no arguments after combining to clear the inherited ordering, or select the field explicitly.
3. annotate(), table, and join aliases are now quoted and case-sensitive
SQL aliases produced by annotate(), along with table and join aliases, are now systematically quoted to prevent collisions with special characters, and quoted aliases are case-sensitive. Raw SQL, anything going through RawSQL or .extra() that references a mixed-case alias by name, may stop matching and needs a look before you ship.
The new calendar-versioning deprecation track
Django is renaming its next two releases under DEP 20, Django's calendar-versioning proposal. What was planned as Django 7.0 is now Django 2028, and what was planned as 7.1 is now Django 2029. Deprecation warnings follow the same rename: RemovedInDjango70Warning becomes RemovedInDjango2028Warning. If your codebase filters warnings by name, that filter needs updating or it'll stop catching anything.
A handful of things are already on that 2028 removal track. Eleven legacy EMAIL_* settings, including EMAIL_BACKEND, EMAIL_HOST, and EMAIL_HOST_PASSWORD, are deprecated. So is calling select_related() with no arguments, django.db.transaction.savepoint() (use savepoint_create() instead), and double-dot template lookups like {{ book..title }}. None of these break yet. All of them will, once Django 2028 lands.
Two features worth adopting during the upgrade, not just surviving it
Two additions in 6.1 are worth adopting, not just working around. The new fetch_mode API, covered in the release notes' rundown of fetch_mode and the new delete options, gives you three explicit options for related-object loading: FETCH_ONE (the default), FETCH_PEERS, and FETCH_RAISE. FETCH_PEERS can reduce most cases of the N+1 queries problem to two queries, a real win if your team has been patching N+1 issues one select_related() call at a time.
Django 6.1 also adds database-level foreign key delete options, DB_CASCADE, DB_SET_NULL, and DB_SET_DEFAULT, that push delete logic to the database instead of Python. DB_CASCADE skips the pre_delete and post_delete signal dispatch, faster on large cascades but silent for any signal handler your app relies on for cleanup or auditing. Adopt it deliberately.
How to plan the upgrade to Django 6.1
1. Audit your database versions against the new floors
Check the actual running versions of Postgres, MySQL, MariaDB, or SQLite in every environment, not just production. Staging and CI runners drift from production more often than teams expect, and SQLite hides in base Docker images nobody's updated in years.
2. Pin your Python version to 3.12, 3.13, or 3.14, latest patch of each
Django 6.1 only officially supports the latest patch release of each series. If your Dockerfile pins an old patch of 3.12, bump it before touching Django itself.
3. Run the test suite with deprecation warnings turned into errors
Set -W error::DeprecationWarning or your framework's equivalent and run the full suite. This surfaces every use of select_related() with no arguments, transaction.savepoint(), and double-dot template lookups before they become 2028 removals.
4. Fix the three backwards-incompatible query behaviors
Search the codebase for order_by() calls with no arguments feeding into first() or last(), for union()/difference()/intersection() calls, and for RawSQL or .extra() calls referencing mixed-case aliases. Each of these needs a manual check; none of them will throw a clean error at import time.
5. Adopt fetch_mode and database-level delete options where they help
Don't rewrite every relation on day one. Start with the queries your monitoring already flags for N+1 problems, and apply FETCH_PEERS there. Add DB_CASCADE only where you've confirmed no signal handler depends on the delete.
6. Schedule the cutover before April 2027
Work backward from the April 2027 end-of-life date with enough buffer for a second attempt if the first stalls. A team without a Django specialist on staff should bring one in early rather than starting the audit in March 2027, and hiring a senior Python/Django engineer who can own this kind of upgrade is usually faster than assigning it to whoever's least busy that sprint.
FAQ
What happens to Django 6.0 after April 2027?
It stops receiving updates entirely. Django 6.0 gets security and data-loss fixes only until April 2027, then it reaches end of life with no further patches of any kind. Running it past that date means running an unpatched framework in production.
Do I need to upgrade Python before upgrading to Django 6.1?
Possibly. Django 6.1 only supports Python 3.12, 3.13, and 3.14, and only the latest patch release of each series. If your team is still on an earlier Python version, that upgrade has to happen first, and it's worth doing before you touch Django code so you're not debugging two moving parts at once.
What is Django 2028?
It's the new name for the release previously planned as Django 7.0, under a calendar-based versioning scheme introduced via DEP 20. The release after that, previously 7.1, becomes Django 2029. Deprecation warnings are renamed to match, so RemovedInDjango70Warning is now RemovedInDjango2028Warning. Anything currently deprecated, including the legacy EMAIL_* settings and argument-less select_related(), is scheduled for removal on that track.
