How to Update Custom Code for Drupal 10: A Step-by-Step Guide

Drupal 10 was released to big fanfare on December 14, 2022. As of March 13, 2023, 75.4% of the top thousand most used contributed extensions are compatible. On the other hand, your custom modules and themes are your responsibility to update, nobody else will do it for you. So let's see what are the key tools and things to keep in mind to make those compatible.

Drupal 7 and 9 users can update to Drupal 10

Drupal 8 to Drupal 10 updates are not supported directly, due to the missing update functions and lack of deprecated API definitions that the helper tools rely on to guide your update process. So if you are on Drupal 8, you'll need to first update to Drupal 9.

For those on Drupal 7, you will need to do a full site migration to get to Drupal 10, that is a supported path, but it will be significantly more work compared to updates from Drupal 8 onwards. Our previous post "What does it take to upgrade from Drupal 7 to Drupal 10?" covers that process, so we will focus on Drupal 9 sites in this one.

1. First update to compatible contributed projects

Before you start working on your custom code, make sure to update to Drupal 10 compatible versions of any contributed projects used on your Drupal 9 site. Some of your custom code may be adding missing features to one or more of those contributed projects or serve as glue between them. So before you update your own code, it is important to update the underlying dependencies. Use Upgrade Status to get suggestions on what needs updating and Composer to actually perform the updates.

There may be contributed projects that did not yet release a compatible version. In these cases, a compatibility issue is often in their respective issue queue. When you are confident in the quality of patches in those issues, you can use the composer-drupal-lenient plugin in combination with composer-patches to apply the fixes locally.

2. Analyze your custom code for changes needed

Now that you have updated your contributed projects and are still on Drupal 9, you can move on to identify what needs to be done about your custom code. Again, Upgrade Status will be your key tool, but in this case, you should use the full code analyzing features to get a list of what needs to be changed. Upgrade Status will attempt to find all changes needed in custom modules and themes alike. A report will look something like the following:

Upgrade Status results for custom module


Issues found are broken down into whether you can automate fixing them. Drupal Rector will explicitly be suggested when automated fixes are available for a change that is needed. Add Drupal Rector as a development dependency and copy the default complete rector configuration provided to the project root directory with the following commands:

$ composer require palantirnet/drupal-rector --dev
$ cp vendor/palantirnet/drupal-rector/rector.php .

Next, use Rector to either generate the suggested changes needed or execute the changes themselves right away. A dry run where changes are suggested but not performed looks like this:

$ vendor/bin/rector --dry-run process web/modules/custom/mymodule
 2/2 [▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓] 100%
1 file with changes

1) web/modules/custom/mymodule/mymodule.module:5

    ---------- begin diff ----------
@@ @@
  * @return void
 function mymodule_alter_world() {
-  $path = drupal_get_path('module', 'mymodule');
+  $path = \Drupal::service('extension.list.module')->getPath('mymodule');
   // ....
    ----------- end diff -----------

Applied rules:
 * DrupalGetPathRector

 [OK] 1 file would have changed (dry-run) by Rector

Assuming you are using a version control system to maintain your custom code, it should also be safe to actually perform the fixes and review the changes with your version control system.  Some of the suggested updates may require manual intervention and may include comments suggesting what to consider to validate the change.

Once you are happy with the automated fixes there may still be issues that need manual attention, even updating compatibility in the info.yml file is one such change. Return to Upgrade Status and re-review what manual changes may be needed still. The report will include links to documentation on to help guide you develop the proper fix for each case.

While Upgrade Status and Drupal Rector are not perfect, they will cover the large majority of problems to fix. If you have a test suite for your custom code, making sure those are green with the new version would of course be crucial. If you lack tests for your custom code, then manual testing would help make sure you can be confident about compatibility.

3. Special considerations for Symfony API users

If your custom code makes use of Symfony APIs, you may need to do an extra step. Drupal 10 updated from Symfony 4 in Drupal 9 to Symfony 6. Because this jumping two major versions, not all of the deprecated APIs of Symfony 5 will be present on your Drupal 9 site. The first alpha version of Drupal 10 was released with Symfony 5 to support those that need this interim step.

If you make use of Symfony APIs, to be sure that you don't rely on Symfony 5 deprecated parts, follow these steps. Once your site is ready to update to Drupal 10, update to Drupal 10.0.0-alpha1 first, then run Upgrade Status on that version to make sure you catch any Symfony 5 deprecated APIs. Fix them in your custom code and then update to a stable version of Drupal 10.