Last updated June 3, 2020

There's no one-size-fits-all path to upgrade from Drupal 8 to Drupal 9, but there is a set of common tasks that everyone will need to complete.

In this tutorial we'll:

  • Explain the differences between Drupal 8 and Drupal 9 that affect the upgrade path.
  • Walk through the high-level steps required to upgrade from Drupal 8 to Drupal 9.
  • Provide resources to help you create an upgrade checklist and start checking items off the list.

By the end of this tutorial you should be able to explain the major differences between Drupal 8 and 9, audit your existing Drupal 8 projects for Drupal 9 readiness, estimate the level of effort involved, and start the process of upgrading.

Goal

Create a Drupal 9 upgrade checklist, and understand what's required to complete the items on the list.

Prerequisites

Differences between Drupal 8 and Drupal 9

From a technical perspective Drupal 9.0.0 is Drupal 8.9.0 with all of the deprecated code removed. There are no significant schema changes, or feature additions, that would require a complex upgrade. As long as all of the code in your project is using the current APIs the transition from Drupal 8.9.0 to Drupal 9.0.0 shouldn't be any more complex then the move from 8.8.x to 8.9.0.

Drupal 9 API is Drupal 8 API with deprecated code removed and 3rd party dependencies updated

Graphic by Gabor Hojtsy

Drupal 9 also includes major version updates to many of Drupal core's dependencies, including Symfony and Twig. If you've got code in your project that relies on an older version of these dependencies that code will need to be updated, too. This is less likely to impact you directly, but it's good to be aware of this change.

Also, in Drupal 9, the Place Blocks and SimpleTest modules have been removed and replaced with Layout Builder and PHPUnit, respectively.

Since Drupal 9 is Drupal 8.9 with the deprecated code removed, a module that's not using any deprecated APIs, and has added the required content to its info file to declare that it's compatible with Drupal 9, should work with either major version. If you've used Drupal for a while this is new, and not how upgrades have worked in the past. But, it's so much better.

When should I upgrade to Drupal 9?

Short answer; When your code is ready.

The primary consideration should be wether or not the contributed modules you rely on, and your own custom modules, are Drupal 9 compatible. Once they are, there is no reason to not upgrade.

If you're using Drupal 8 you have until November 2021 to complete your upgrade. At that point, Drupal 8.9.x will be unsupported and Drupal 8 will have reached it's end of life. This is also the current Drupal 7 end of life date, but there are plans to offer extended support. Read more about Drupal core release cycles.

We like this article as a guide to figuring out when to upgrade: When to Upgrade from Drupal 8 to Drupal 9

Drupal 9 upgrade checklist

Make sure you can check off all the items in the list before you upgrade to Drupal 9.0.0:

Update to Drupal 8.8.x or 8.9.x

Before you upgrade to Drupal 9 you need to be on the latest version of Drupal 8.

Learn how to perform a minor version update.

Update all your contributed projects

You should update all your contributed modules and themes to Drupal 9 compatible versions while you're still on Drupal 8.

It's a good idea to update all your contributed modules and themes to their latest versions as well. Before you can upgrade Drupal core to version 9, you'll need to ensure that all of your contributed projects are already Drupal 9 compatible. In most cases this will mean updating to the latest version. In some cases this may require additional work if the module isn't already Drupal 9 ready.

Look at the project's page on Drupal.org for more details about compatibility:

Screenshot of project info data from the Consumers project page with info about Drupal 9 highlighted

Acquia has created a useful tool for checking compatibility.

These are good for getting an estimate of what's going to be involved for your project.

When you're ready to start working on the Drupal 9 readiness of the modules installed on your site, use the Upgrade Status on your current site to generate a report. And help fix some common issues. Learn more about using Upgrade Status.

If a module isn't Drupal 9 compatible you've got a few options:

  • Update it yourself. This similar to updating custom code. See below.
  • Wait for a future release of an updated Drupal 9-compatible version.
  • Hire someone to do the updates for you.

We recommend starting with your custom code. And once that's done, come back to your contributed modules and figure out which ones are the most critical for your project and see what you can do to help update them for Drupal 9. In many cases there's likely a patch already available and waiting for community members to test it out.

Update your custom code

If your project has custom modules or themes, it's your responsibility to ensure that that code is compatible with Drupal 9.

You can use Upgrade Status to scan these projects as well. And then you'll need to remove all use of deprecated APIs. Learn more about what deprecated code is and how to deal with it.

Tip: Even if you're not planning to upgrade to Drupal 9 now you should start doing this. It'll save time in the future, and since Drupal 9 is backward-compatible with Drupal 8.9 it shouldn't affect your existing site.

Verify your hosting meets the new requirements

The hosting environment requirements for Drupal 9 have changed. You'll want to make sure your web server, PHP, and MySQL/MariaDB are all running compatible versions.

Upgrade Drupal core

These instructions assume you that your Drupal 8 project is using Composer to manage dependencies, and that you either started from the drupal/recommended-project Composer template. Or, you've updated your composer.json to use the drupal/recommended-project's approach to scaffolding. If you're unsure look for an entries like "drupal/core-recommended": "^8.8", and "drupal/core-composer-scaffold": "^8.8" in your composer.json file. This is a good indication that you're using the current recommend approach.

You can learn more about making these changes in Update Drupal from Versions Prior to 8.8.x using Composer.

Note: Using the --no-update flag updates the composer.json entries, without attempting to resolve and download any files. This allows us to batch updates to projects and avoid a "chicken-or-egg first"-type of issues with shared dependencies. Alternatively, you can edit the version constraints in composer.json manually.

If you have the drupal/core-dev dependencies installed you'll need to update those:

composer require drupal/core-dev:[email protected] --dev --no-update --update-with-dependencies

Then update the drupal/core-recommended and drupal/core-composer-scaffold projects:

composer require drupal/core-recommended:[email protected] drupal/core-composer-scaffold:[email protected] --no-update --update-with-dependencies

Then tell Composer to try and resolve and download all the new code:

composer update

If this is successful you'll see line like the following the output:

  - Updating drupal/core-dev (8.8.7 => 9.0.0)

If you get any errors you'll need to troubleshoot what's causing the issue. We've tried to provide guidance on some common ones below.

Troubleshooting a Drupal 9 upgrade

Problem: Permission denied updating files in sites/default/

In some cases you may need to modify the permissions on the sites/default/ directory, and files within it, so that they can be modified.

Solution: Set them to something more permissive:

chmod 777 web/sites/default
find web/sites/default -name "*settings.php" -exec chmod 777 {} \;
find web/sites/default -name "*services.yml" -exec chmod 777 {} \;

Important!: Remember to set permissions back after completing the update:

chmod 755 web/sites/default
find web/sites/default -name "*settings.php" -exec chmod 644 {} \;
find web/sites/default -name "*services.yml" -exec chmod 644 {} \;

Problem: Composer can't resolve an installable set of packages

If running composer update results in message saying, "Your requirements could not be resolved to an installable set of packages.", there's a good chance that one or more of your contributed modules isn't Drupal 9 compatible. (Or at least the current release version of the project isn't.)

Solution: Look for lines like this in the output:

- drupal/recurly 1.5.0 requires drupal/core ~8.0 -> satisfiable by drupal/core[8.8.6, 8.0.0, 8.0.0-beta10, ...

This indicates that the drupal/recurly project requires Drupal 8.x, but we're asking for Drupal 9.x, therefore resulting in an incompatible set of dependencies.

If there's a -dev version of the module that you know is compatible with Drupal 9 you could try installing that.

Example:

composer require drupal/recurly:1.x-dev --no-update

If there's a patch in the issue queue see the next tip.

Problem: The contributed module I'm using has a patch (but not an official release) that makes it Drupal 9-ready

Often times modules without a Drupal 9 compatible release will have a patch in the issue queue that makes the module work with Drupal 9, but hasn't been committed by the project maintainers yet.

This can result in a sort of race condition, where Composer can't download the required module because it's not presenting as Drupal 9 compatible, so you need to apply a patch, but Composer can't apply the patch if it can't resolve the dependency tree first.

Solution: We recommend adding the modules you need patched to your Git repository, patch them, and stop relying on Composer to download them for now. Similar to how you might manage custom modules. Then switch back to including them via Composer once the patch has been applied.

If that's not an option, you could also try and use Composer aliases. We recommend this as a temporary fix only, and suggest working with the contributed module maintainer to get the patch committed ASAP.

First, patch the module in Drupal 8, prior to trying to move to Drupal 9, and confirm that it works. Learn more about applying patches via Composer.

Example from composer.json:

    "extra": {
        "patches": {
            "drupal/recurly": {
                "Drupal 9 readiness": "https://www.drupal.org/files/issues/2020-01-29/3109436-5.patch"
            }
        },
    }

Then in your composer.json add a line like the following which will alias Drupal 9 to Drupal 8. Which should allow the dependency tree to resolve.

"drupal/core": "9.0.0 as 8.9.0"

Note that you'll need to use full tag or branch names and not standard Composer version constraints when creating aliases like this. So, change 9.0.0 to the latest release of Drupal 9, and 8.9.0 to the latest release of Drupal 8.

Then run composer update.

Recap

In this tutorial we looked at what's involved in making the transition from Drupal 8 to Drupal 9. This included going over the differences between the two, auditing your custom and contributed modules for compatibility, learning how to make things Drupal 9 compatible while still using Drupal 8. And then finally upgrading Drupal core once everything else is ready, and some troubleshooting tips for common problems.

Further your understanding

  • Most of the Composer commands above can be replicated by directly editing your composer.json file, and then running composer update.
  • If you're using Drupal 7, upgrading to Drupal 9 still requires a major migration. See our Drupal Migration Guide.

Additional resources