Skip to content
Frameworks Article

Django Goes Annual and Makes Every Release an LTS

Starting January 2028, calendar versioning and universal three-year support replace Django's two-tier LTS system.

Lenn Voss
Lenn Voss
Cloud & Infrastructure Writer · Aug 10, 2026 · 4 min read
Django Goes Annual and Makes Every Release an LTS

Django announced today that it's scrapping its eight-month release cycle. Starting January 2028, the framework ships one feature release per year, numbered by calendar year — Django 2028.0, then 2029.0 — and every release gets three years of support: one year of mainstream bugfixes, two more of security and data-loss fixes.

The headline reads like a scheduling tweak. The real story is buried one layer down: Django is retiring the LTS label entirely. After a decade of running a two-tier support system, the project has effectively concluded that LTS tiers were an anti-pattern — one that trained most of its users to skip releases — and the fix is to make every release an LTS.

What actually changes

The accepted proposal, DEP 20, authored by former Django Fellow Carlton Gibson, lays out the mechanics. Feature releases land mid-January, preceded by an alpha in October (right after CPython's annual release), a beta in November, and a release candidate in December. Versioning switches to CalVer in the form YYYY.N: 2028.0 is the feature release, 2028.1 the first patch, 2029.0 the next year's release. At any moment three versions are supported — the current one getting real bugfixes, the two before it getting security patches.

The transition is deliberately boring. Django 6.1 (August 2026) and 6.2 LTS (April 2027) run out their advertised support windows on the old rules — 6.2 is covered through April 2030. What would have been Django 7.0 in December 2027 becomes 2028.0 in January 2028. Nothing changes before then.

Python alignment is a first-class design goal. Each Django release supports the three latest Python versions at launch and picks up October's new CPython in a patch release during its first year. That kills a long-standing maintenance absurdity: under the old scheme, LTS releases dragged a wide Python matrix deep into obsolescence. Django 4.2 was still shipping security fixes for Python 3.8 setups in early 2026, a year and a half after Python 3.8 itself went end-of-life.

The LTS trap Django built for itself

The old cadence — two eight-month feature releases, then an LTS, repeat — looked reasonable on paper and produced perverse incentives in practice. Because only every third release carried long support, cautious teams learned to ignore the other two. Gibson's numbers make the damage concrete: at any given time, only 50–70% of Django's PyPI downloads were for a supported version. The framework with arguably the best backwards-compatibility discipline in web development had a third to a half of its installed base running unsupported code.

LTS-hopping also made upgrades worse, not safer. Jumping 4.2 to 5.2 means absorbing two years of deprecations in one sitting, usually under deadline pressure as the old LTS approaches end-of-life. Third-party maintainers got squeezed from both ends — pressured to keep supporting the previous LTS long past its official death, with little incentive to certify against non-LTS releases few production users ran.

Other ecosystems have been converging on the same answer for years. Python itself went annual with PEP 602. Node cuts a new LTS line every October. JetBrains has used the exact YYYY.N scheme since 2016. What's notable is that Django went further than most: Python considered calendar versioning in PEP 2026 and rejected it; Django looked at the same arguments and took the leap. For a 20-year-old project famous for conservatism, that's a strong signal of how badly the old model was working.

What to do with this

If you run Django in production, your upgrade playbook changes in 2028, and the new one is genuinely simpler.

The annual hop becomes the default strategy. Upgrade each January (or whenever the .1 lands, if that's your temperament) and your delta is always one release — one set of deprecation warnings, one changelog. The old LTS-to-LTS guarantee generalizes cleanly: clear all deprecation warnings on your current release and you're safe to jump, because removals still trail deprecations by two releases. Under annual cadence that's 24 calendar months of warning instead of 16, so even the maximum in-support jump — say 2028.0 straight to 2030.0 — is no worse than today's LTS hop, on a schedule you can put in the calendar three years out.

Pinning gets easier, but check your tooling's assumptions. Django~=2028.0 does exactly what you want — patches only ever increment N, so PEP 440 compatible-release pins track a support window precisely. The thing to audit is anything that treats Django's version semver-ishly: Renovate or Dependabot rules that auto-merge "minor" bumps will see 2028.0 → 2028.1 as minor (fine, it's a bugfix) but also 2028.x → 2029.0 as major-ish depending on config. Worth a dry run before 2028.

Library maintainers get a fixed-size matrix. Three supported Djangos times roughly three supported Pythons, rolling forward once a year each, on predictable dates. Compare that to today, where a conscientious package tests against a jagged set of LTS and non-LTS versions with staggered EOLs. Downstream projects that key their own schedules off Django's LTS rhythm — Wagtail is the obvious one — will need to re-plan, but against a much steadier target.

The honest trade-off

Features now ship every twelve months instead of eight, and a January miss means a year's wait — that's a real cost, and the DEP admits it. But it's the right trade. Django's bottleneck hasn't been feature velocity for years; it's been getting the installed base to actually move. A release cadence is a user-behavior design problem, and the old design produced 30–50% of users on dead versions. If universal three-year support gets the annual hop to become the norm, the community upgrades faster on a slower cycle.

The prediction worth making: Django won't be the last. Every framework running a two-tier LTS scheme has the same skipped-release pathology in its download stats, whether it's measured it or not. Django just published the diagnosis and shipped the cure. Expect the "every release is an LTS" model to start showing up in other projects' governance proposals within a couple of years — and expect the holdouts to keep wondering why nobody upgrades.

Sources & further reading

  1. Django is moving to an annual release cycle — djangoproject.com
  2. Django moves to an annual release cycle — lwn.net
  3. DEP 0020: Annual Release Cycle — github.com
  4. An Annual Release Cycle for Django — buttondown.com
Lenn Voss
Written by
Lenn Voss · Cloud & Infrastructure Writer

Lenn writes about cloud platforms, Kubernetes internals, and the infrastructure decisions that quietly make or break engineering organizations. Based in Berlin's vibrant tech scene, they have a talent for turning dense platform-engineering topics into prose that people actually finish reading.

Discussion 0

Join the discussion

Sign in or create an account to comment and vote.

No comments yet

Be the first to weigh in.

Related Reading