Drupal 9 upgrade from Drupal 8

By Oliver Davies

As of November 2021, Drupal 8 will no longer be supported, meaning now is the time to upgrade to ensure your site’s security and take advantage of all the features that were developed in Drupal 8, just on a 'leaner, cleaner codebase'. Having developed the Inviqa sites on Drupal 8 two years ago, I was keen to upgrade the inviqa.com and inviqa.de to Drupal 9 as early as possible, and share the learnings.

We are glad to say that this upgrade was a much simpler and quicker process than our upgrade from Drupal 7 to Drupal 8 in October 2019. That was a big project, starting with a new and empty code repository, re-architecting the site’s content, and writing new custom modules and themes - essentially starting again from scratch.

Under the hood, a lot changed between Drupal 7 and 8 with the switch to primarily object-orientated PHP code, adding a number of Symfony components and other third-party dependencies, a new templating engine (Twig), and a new dependency management tool (Composer).

Because of these changes, moving from Drupal 7 to 8 was a case of starting again, migrating the data that was needed, and attempting to update and re-use any applicable code - rather than a simple upgrade between versions like this project.

No big rebuild

As Drupal 9 was built in Drupal 8 with a minimal number of breaking changes, modules and themes that were originally written for Drupal 8 can also work in Drupal 9 at the same time. That means that a 8.x-1.0 version of a module could also support Drupal 9 (and also why contrib has moved to semantic versioning to make that clearer).

8.x release of a contrib module with Drupal 9 compatibility.
8.x release of a contrib module with Drupal 9 compatibility
Release of contrib module using semantic versioning, compatible with Drupal 8 and 9.
Release of contrib module using semantic versioning, compatible with Drupal 8 and 9

Because of this, we were able to do the majority of the upgrading within the Drupal 8 versions of the sites. The majority of the modules that we use have versions that are both Drupal 8 and 9 compatible, so we could update those before updating Drupal itself.

For our custom code, we've been able to remove usages of deprecated code (code that was marked as to be removed in Drupal 9) during the Drupal 8 lifecycle, so our theme and the majority of our modules just needed their .info.yml files to be updated to signify that they were D9 compatible.

Doing so is a simple, one-line change:

- core: 8.x

+ core_version_requirement: ^8.8 || ^9

The old core key only accepted a single value for which version of Drupal a project was for, but the core_version_requirement that was added in Drupal 8.8 allows adding multiple versions - such as 8 and 9 simultaneously.

We used tools like the Upgrade Status module and the Drupal Check tool to see our progress and to search for deprecated code that would need to be upgraded, and also relied on our existing automated tests and quality checks to ensure that things continued to work as expected.

Incremental upgrades

All of the changes so far were backwards-compatible, meaning that they worked with both Drupal 8 and 9, so we were able to split them across different pull requests which made them easier to review, and into separate releases and deployments so that they could be tested separately and minimise the risk compared to releasing everything at the same time.

If we found an issue due to one of the changes, we could revert that single change rather than needing to revert the sites back to Drupal 8.

Different pull requests
Different pull requests

Updating Drupal with Composer

After all of the other updates, we were able to update Drupal using Composer. We use the drupal/core-recommended project as well as drupal/core-composer-scaffold and drupal/core-dev. For each of these, we updated the versions from ^8.9 (anything greater than or equal to 8.0.0 but not 9.0) to ^9.0.0 (anything greater than 9.0.0 but not 10), following the Composer recommendations on Drupal.org.

With the composer.json file updated, and due to the sites' additional dependencies, this is the command that we ran to update Drupal:

composer up drupal/core-* --with-all-dependencies composer/installers symfony/* consolidation/* tightenco/collect

This upgraded the Drupal core packages from 8.9.14 to 9.1.8, as well as updating those packages' dependencies.

Breaking changes

Once we had applied all of the backwards-compatible changes, there were also some breaking changes that would apply only to Drupal 9 but, because of the incremental release approach, we were able to group these into a single deployment.

Some modules had different versions for Drupal 8 and 9 but not one for both. In this case, it needed to be removed and the new version added once Drupal was updated.

Separate releases for a contrib module, one with Drupal 8 compatibility, one with Drupal 9 compatibility.
Separate releases for a contrib module, one with Drupal 8 compatibility, one with Drupal 9 compatibility

Some modules didn't have Drupal 9 versions so we needed to apply patches from their issue queues to make them compatible. This was easy to do using Composer plugin called Composer Patches which means that they were applied automatically and again when those modules are updated.

We did have an issue with a Drupal 9 version of a module but we were able to fix it using Drupal's change records as a guide, and submit a patch to the module to fix the issue.

In summary

We upgraded the inviqa.com and inviqa.de websites from Drupal 8 to Drupal 9 with no large rebuild, keeping all of our custom modules and themes (with some very slight modifications), no downtime, and over several releases to make reviews easier and to minimise the risk between deployments.

We created, reviewed, and merged 4 internal pull requests, updated 15 Drupal modules to their Drupal 9 compatible versions, applied patches to 4 modules (one of which we wrote and contributed), and updated a total of 59 files to complete this upgrade.

The previous Drupal 7 to 8 project took a team of Engineers, Designers, UX'ers, and Project Managers to deliver over several months, whereas this Drupal 9 upgrade was done by one Engineer over just a few days (in terms of the actual allocated time) and I've heard others tell the same story.

As Dries Buytaert said in his Drupal 9 blog post:

The big deal about Drupal 9 is that it should not be a big deal