And yet those environments wouldn’t pay for a commercial Django license with longer security updates either, would they? I work in a highly regulated industry and frequent updates not being acceptable is imo most of the times just a cheap excuse.
I really appreciate that. Practically speaking, it seems that your magic wand doesn’t exist, barring simply making our release cycle slower. In practice it seems that we can’t reasonably add new features without also breaking compatibility in enough ways that make us unable to recommend hopping from LTS to LTS directly.
In your view, does the somewhat-adhered-to compatibility between N.2 and (N+1).2 make a significant difference in whether someone attracted to LTS is likely to use an LTS, or might abandon Django altogether?
I suspect that such attempted compatibility is adding a non-trivial maintenance burden without providing the benefit that would be worth the cost for our fellows and community. However, I suspect that just having the LTS releases, without any additional compatibility guarantees, might reasonably be a significant factor in why Django is attractive to sponsors.
There are some cases where this is true - and some where I don’t think the answer is quite so clear-cut.
For example, and only for discussion purposes, we were directly affected by the following items deprecated in 4.2, available in 5.0 and removed in 5.1:
- make_random_password() removed
- UnsaltedMD5PasswordHasher removed
- length_is template filter removed
Now, were any of these so technically problematic that they couldn’t have been kept until 6.0? (That’s an honest question to which I do not know the answer. If the answer is “yes”, I can accept that.)
To be clear, I would also add that I would have been fine if these specific examples had been dropped in 5.0 - their effects on us were minimal.
I am only pointing these out to identify specific examples where I disagree with the current deprecation policy WRT the “pseudo-SemVer” numbering scheme. These removals feel to me like it breaks the spirit of an X.0 → X.1 transition.
Or, to try and explain it another way, I fail to see a “difference in severity” implied by the X.0 → X.1 transision as compared to a X.2 → X+1.0. I’m not familiar with any other project that would consider those two transitions to be “equal”. (There may be some, my knowledge is far from complete.)
There’s another incongruity between the X.0 → X.1 transition and the X.1 → X.2 transition in that while features can be removed in X.1 they will not be removed in X.2
This does not make it “wrong” in any objective sense, just different.
Speaking for myself as an individual formerly employed by an organization and not as a representative of that organization, the decision to migrate from LTS to LTS has been made based on staffing and funding issues, not technical issues regarding the magnitude of changes.
For certain projects, the actual amount of time spent updating the code is generally quite small compared to the administrative costs associated with deploying new releases. Going through the release process every 8 months simply wouldn’t happen.
So they migrate from LTS to LTS to take advantage of security patches over a 2-year window, keeping the release cadence at an appropriate rate. (I am not aware of any situation where a security release has cause an issue - those are frequently slipstreamed in with little difficulty.)
But this is primarily true for a very small number of projects. There are other projects that are updated regularly, and projects of very limited scope that may never get updated. (Those projects run in a physically isolated equipment “test bench” environment. I wouldn’t be surprised to find a 2.2 project still hanging around somewhere.)
As far as I can all of those could have kept “easily” till 6.0 (and 10.0 [sic] for that matter). The crux is probably in the detail, what does “easily” mean? It is easy to not remove code (sometimes) but it also means more CI time, potentially more bugs to fix, more code to navigate when developing a new feature etc…
Worse, when people only migrate from LTS to LTS we get bug reports about new features very very late after their initial commit.
I agree that the current versioning scheme might be a bit odd about when features are removed wrt LTS, but I don’t have strong feelings on version numbers ![]()
What would be a way to force those projects to lower those administrative costs and put some of the money gained elsewhere (like Django)? In the end it feels like we are selling Django way to cheap if there is no incentive to lower those administrative costs. Take a look at Spring Boot for example, you get 13 months (iirc) support and then you pay for Spring Enterprise. Now I get that not that many projects have such policies like the ones you mention; but as a larger community how much do we want to “work” (as in: developing Django) for those instead of the other ones that keep up with releases etc?
Agreed completely, if the “meaning” of those numbers can be understood.
Side note: We’re getting pretty far afield from the original topic being the version numbering system used by Django. I think if this discussion is to continue, we might want to move these messages to create a new thread. (Your “friendly local moderator” does know how to do that.)
Not possible - and it’s not at all related to the technology being used.
It wouldn’t matter if the stack being used was Java Spring, Drupal, or even Microsoft Excel. The overhead for getting approvals to update anything can be substantial, but necessary within the context of the larger environment of which these software development tasks are a very small part.
I have always considered myself an outlier in terms of how we use Django. I never expect that anything be done “for” us, but have only ever requested that changes not be made “against” us. (e.g. The thread from a while ago where the idea was floated to eliminate the manage.py file.
As such, we adapt ourselves to the LTS release cycle rather than requesting changes be made to that cycle to benefit us.
This also means I would continue to advocate for some type of “LTS” release that remains supported for security purposes for at least 25 months total. (The 36-month window is perfect for us.)
I can understand that (one of) the DSF or the TSC could decide that the maintenance effort of an LTS release is not justified, and that they would be stopped. Personally, I can understand the decision, but also think that would be a mistake - but that’s from my perspective as an outlier. (What my former employer would do is something they would need to decide.)
At the risk of continuing this off-topic conversation too much, I’m more interested in the idea of having no guarantees about compatibility between LTS releases than I am in abandoning LTS entirely. I think that having the extended support of LTS releases encourages sponsors. I’m not sure that attempting any additional compatibility between those releases does, however.
If we dropped any special compatibility between LTS releases, I wonder how much comparative burden on the fellows it might be to extend all releases to be longer-term supported for security. I assume a notable amount of additional burden, but it could be something to consider.
For example, if we unified extended support to 32 months, then the end of extended support would align with new Django releases. We’d have mainstream support for 1 cycle (8 months) and extended support for an additional 3 cycles.
This would be more similar to Python’s yearly cycles, except that we’d have one less cycle than Python for mainstream (active) support, with the same number of extended (security-only) support cycles. This more predictable pacing could also aid our ecosystem packages in better aligning with our pace.
And just to give it an on-topic flavor: I like that the versions reflect our usual steering council terms. That’s a boundary where priorities for the project could be more likely to shift in notable ways as the governance of the project changes.
Just to wrap up here, I had more thoughts on what might work here.
Here’s my proposal to move Django to an annual release cycle.
It’s obviously a bit spicy ![]()
![]()
so no idea how that’s gonna go but ![]()
That’s still the other option.
@carltongibson Great write-up!!! I’m trying to understand why the below is not considered an option? I.e. aligning current release cycle with the calendar year, but skip the version scheme changes?
| Existing | Proposed | Release Date |
|---|---|---|
| 5.0 | 5.0 | Dec ‘23 |
| 5.1 | 5.1 | Sep ‘24 |
| 5.2 LTS | 5.2 LTS | Apr ‘25 |
| 6.0 | 6.0 | Jan ‘26 |
| 6.1 | 6.1 | April ‘26 |
| 6.2 LTS | 6.2 LTS | Sep ‘26 |
(the release months are not a concrete proposal, just examples)
Compromises:
- We switch to an annual rhythm in the release cycle
- LTS releases are the last release of the year
- Easy to learn pattern: “6”+20 = 26
- All the .2s are still LTS releases
- No irreversible changes to versioning (ie. once you go “2026”, you can’t go back)
- It’s still SemVer
- Allows for irregularities so we never need to shoot ourselves in the foot if something disruptive happens.
- We can see how the yearly cycle goes - and if happens to work great for some years, we can decide again if it’s worth using the year as the major digit.
I think a major release every four months would be asking a lot.
I’ve pondered developer friendly preview tags at times, but that’s just an idea — bottom line is I can pip install any given commit for less effort than it’s probably worth.
Happy to go down these side alleys on the social if you want!
I’m roughly favorable to your proposal, Carlton. The consistency and alignment with the cadence of Python seems a great choice. I don’t love the years-as-versions, but they’re ok. 2-digits year versions would be better.
One thing that you didn’t address is the steering council alignment. Right now the steering council is aligned with the first version number changes, but it’s not clear how you would see that mapping to the new versions.
Thanks for this detailed write-up Carlton. I’m +1 on an annual release cycle, and going for “green only” or “plus last yellow” on Python support.
I’m still not sold on renumbering to year-based versions, especially since Python has decided not to use such a scheme. But I also don’t have an amazing suggestion here, since I think it’s in our interest to keep bumping the major version number, but doing it annually and keeping a .0 minor version would look a bit silly.
If we keep the first version aligned with steering council cycles, it could avoid that problem.
To try to understand the package maintainers’ perspective, I’ve set up a Yearly LTS proposal - Wagtail and Django release timeline that others might find helpful, with pretend yearly LTS from 2023 to 2027 in April, to compare with the current Wagtail and Django release timeline.
The proposed schedule seems like more work to me, simply because 3 LTS to support = 3x 36 months? While in the current release schedule, of the 3 concurrent Django releases to support, one is 36 months support and the other two are 16.
I also worry about the crunch if all package maintainers were to look at 12 months’ worth of compatibility changes all at the same time of the year, vs. the current more staggered 8 months. Feels like packages with package dependencies would have a harder time upgrading? Not sure.
Should this be added on the new features repo? I’ve not heard much complaints about Django’s versioning scheme personally, I’d be interested to know how this fares compared to other possible improvements in
metrics.
I like the idea of switching to annual releases, each being 3-year LTS. The slower release pace matches Django being a mature 20-year old core project, where a lot of the innovation happens with 3rd party apps. Fewer releases means apps don’t need to upgrade as frequently. It’s also nice to have the same schedule every year. More frequent LTS releases also gives LTS people the option to upgrade yearly rather than every 2 years, assuming it works with their version of Python.
I think “Green Only Pythons” (currently 3.13 and 3.14) is too limited, and as an Ubuntu LTS user, “Plus Last Yellow” (2-year-old python) (currently 3.12) is pretty key, and would be enough for me. If Django is reaching back 2 years of python and giving 3 years of support, then Django generally doesn’t need to support an EOL python which are supported for 5 years. Aligning Django’s release date (December/January) to be just after Python’s release date (October) really helps with that.
Re versions, if the release was early January, then just do CalVer with month: 27.1, 28.1, etc. (I personally prefer 2-digits, can always switch to 4 later.)