Navigating core_version_requirement

Jakob Perry
4 min readMar 1, 2022

Update (Aug 1 2022):

At Drupalcon Portland, Nicolas Grekas, Gábor Hojtsy, Ryan Aslett, Matt Glaman, had a discussion which basically led to the creation of the drupal-lenient composer plugin. Developers are encouraged to use this plugin when working to update modules to the next version of Drupal.

What should core_version_requirement look like?

My personal preference is to work with the next ‘beta’ of a major version. That allows developers to immediately work with a module, but doesn’t allow it to automatically work with the next stable release:

If your module supports Drupal 8, 9, and 10:
core_version_requirement: >=8.9 <11.0.0-stable

If your module supports Drupal 9 and 10:
core_version_requirement: >=9.2 <11.0.0-stable

Original Post

Back when PHP 8 came out, there was some discussion regarding PHP version support with Symfony. Nicolas Grekas, a Symfony core contributor, made this observation:

https://twitter.com/nicolasgrekas/status/1263023258938548225

The crux of his argument was that by using 7.x, you’re creating planned obsolescence, and by having the ecosystem adopt this system, you’re making it very hard for developers to even experiment with PHP8.

The other untold part of his argument is around ownership and control. Should composer be a hard-lined traffic cop, putting barriers on where code should be allowed to operate? Or should it be more of a guideline?

I totally agree with Nicolas here for PHP. In-fact, Drupal 8+ uses his advice and requires PHP >=7.3 instead of ^7.3. But what about Drupal modules? With Drupal 10 coming soon, should modules be adopting the current recommendation: ^9|^10 ? or would >=9.2 be better going into the future? What about Drupal 8 support? Lets discuss.

First, a look back at #d9readiness.

Drupal 9 was the first version of Drupal to be backwards compatible with Drupal 8, and had minimal changes for sites that were using the latest version. Drupal 8.9 =Drupal 9*. Modules also had a similar experience: those that maintained updates with core were pretty simple to upgrade to Drupal 9. But they had to add/change the core_version_requirement property. This meant many D8 modules that otherwise worked with Drupal 9 would not even pass composer checks due to the missing version compatibility. This made D9 testing very difficult, especially with dependencies if they weren’t Drupal 9 compatible. Only after modules had defined the core_version_requirement could they even be tested to see if they were truly compatible with Drupal 9.

*There were dependency updates, specifically symfony, that makes them not entirely equal. But in general if your module worked with D8.9 with no deprecations, it worked with D9.

Minimum vs Maximum version requirements

I think everyone can agree that setting minimum versions is a good practice. It allows code to use newer software and not have to be backwards compatible. However, to ensure customer success to newer versions of software, I only increase the minimum requirement if the code requires it. Having a larger window of version compatibility ensures customers can upgrade from older projects to newer ones without your module being a blocker.

Maximum’s don’t have this problem with deprecated code. Maximum versions aren’t about saying your code won’t work with software above a specific version, but more “we don’t know so we will just be safe and say it won’t.” In practice this is unnecessary; either the software will work as-is, or will be broken and require maintainer intervention. The problem is, if you set maximum constraints, contributors can’t even test against the version they’re having a problem with!

What about >= 8.9? Drupal 8 is EOL!

While the community has stopped supporting Drupal 8, the reality is thousands of Drupal 8 sites are still in use today. And if you support Drupal 9.0, you already support 8.9. Making it easier for customers to upgrade from Drupal 8 to 10 will be important, and it doesn’t help if we set our minimums too high.

While some will think Drupal 8 is quite outdated, this isn’t really true. Until Drupal 9.3 (November 2021), modules supported 8.9 and 9.2. With 9.3 and certainly D10 there will be new deprecations that will need to be worked around. But Remember: Drupal 9.2 is still supported! Its worth the tradeoff to help pull customers into the D10 ecosystem without having to do an intermediate upgrade to Drupal 9.

If your module supported Drupal 8 until recently, consider keeping the ≥8.9 constraint until after Drupal 10 is released.

Remove maximums for Core only

We’re lucky that at this point, Drupal core has become a very stable, well planned out software project. Its that trust, coupled with the d8+ major version policy, that allows this to work. That is not the case for contrib. The lack of consistency between projects and the fact that different versions may support entirely different dependency paths and data structures means you definitely should use maximum constraints for contrib modules in your own module’s composer file.

Which version should I set as a minimum?

Whatever minimum you currently have should be the constraint going forward: (^ 8.9 | ^ 9 ) should be rewritten: >=8.9 <11.0.0-stable

If your module supports only Drupal 9 and 10: >=9.2 <11.0.0-stable

What about deprecations?

As we get into deprecations, the following ugly code will be needed:

//TODO: Remove when support for Drupal 9.2 dropped.
if (version_compare(\Drupal::VERSION, ‘9.3’, ‘>=’)) {
$rendered = \Drupal::service(‘renderer’)->render($image);
}
else {
// @phpstan-ignore-next-line
$rendered = render($image);
}

The above code will allow earlier versions of Drupal to work with the render function, while supporting the new version in 9.3. If your code only has a few of these programmatic changes, its worth the tradeoff to allow lagging customers to get upgraded without extra hurtles.

Removing maximum limits to core_version_requirement will help speed up the pace to adopting the next major version of Drupal core.

--

--