Drupal 9 Upgrade: Start to Finish

Good news: after all the sweat and blood of getting our site ready, the upgrade took all of 30 minutes. This really may be the easiest Drupal upgrade in a decade. It's still not for the faint of heart. Here's a quick recap on the steps necessary to do this upgrade. I'll be sure to link back to my previous articles so you can see the work and challenges involved with each step in detail.

Drupal 9 Up Front

Compared to all the work that went into prepping the site, the actual upgrade is a walk in the park. I'll be sure to cover the actual upgrade process in Step 5 of this article; I'd like to do a quick recap on the entire process, though--so, if you've already read my earlier Drupal 9 Upgrade posts, feel free to skip to Step 5. Otherwise, let's reconnect with what the basic steps are for a D8 to D9 upgrade.

Step 1: Outlining the Upgrade

The literal first step in the upgrade has little if anything to do with Drupal; the first step is to visualize and create a chronological account of what the process as a whole will be. While Drupal.org claimed that this would be the easiest upgrade in a decade, having done a D7 to D8 migration not long ago (a process that took nearly two months, as I recall), I wanted to play it safe and begin with an outline. After a little research (a MUST read) it seemed that the logical progression should be more or less, this:

  1. Outline chronology
  2. Setup a virtual localhost to keep my existing D8 development machine isolated and clean
  3. Determine which, if any, modules would be affected by the upgrade
  4. Module remediation
  5. Perform the D9 upgrade on the VM
  6. Make ready to bring the D9 branch into DEV
  7. Push D9 to PROD
  8. Afterthoughts

It wouldn't really have been possible to put an ETA on project completion without knowing how many modules would need remediation (or how much remediation they would need). Still, having a general outline of the steps to "go live" can help give the project both direction and momentum--things I wanted very much to have after my last big upgrade.

Step 2: Setting up a VM

This may not be necessary for everyone. I had reasons to do this, though, since my work machine is on a different version of PHP than the one we'll use for D9. Another reason for the VM was not having Drush set up on my work machine; I needed to get it set up without disturbing ongoing workflow. Lastly, the move to Composer (albeit, overdue) had me concerned as well. Both Drush and Composer can be installed globally, which means that the potential to screw up root directories on my work machine is real (I once wiped my entire machine clean with an erroneous command at root--live and learn).

I entertained giving DrupalVM a try, but for the sake of time I opted for something more familiar: using VirtualBox I got a quick install of Ubuntu going, installed XAMPP and cloned our repository & files onto the machine. I branched out and began getting my hands dirty. There were a few issues with getting Composer to play nice with XAMPP at this stage.

Step 3: Determining Affected Modules

I had meant to put together a more detailed post on this step and never got to it. The best tool for helping you address this step is a module called Upgrade Status (I talk about installing the module in that first Composer gripe article). This module will give you an overview of where all your modules stand in regard to Drupal 9 readiness. You simply select modules you'd like Upgrade Status to scan and it will let you know what the module needs in order to reach compatibility.

Step 4: Remediation

In most cases, affected modules will simply need an update or a patch. The Upgrade Status module will let you know when a module update is available. The first step in remediation, for me, was to go in and update these modules with Composer. I posted an article on the difficulty of getting Composer to update modules into the correct directory--beyond that, updates aren't particularly daunting. Some modules will not yet have an official update addressing D9 compatibility. For these, you're likely to find that the contributors have already put together patches for their development branches. Applying patches to modules is slightly daunting if you've never done it before, but once you find your rhythm it's not particularly overwhelming.

The remediation process is a good opportunity to retouch which modules you need and which ones you might like to let go of. I wound up uninstalling a handful. These modules might have had a path to D9 compatibility, but I simply opted to let go of them. One notable mention, however, is the Taxonomy Manager module. This module, for whatever reason, didn't seem to have a version, -dev or otherwise, that was compatible with both D8 and D9. This meant uninstalling it in order to do the upgrade; now that the upgrade is complete, I will likely go in and reinstall it.

Step 5: The Upgrade!

The trick is to follow the Drupal.org upgrade instructions to the letter. There are five steps in this process; two of them are a little trickier than the others, but nothing particularly daunting. Let's look at the first of these two: running the actual upgrade with Composer. If you've been patching your modules, much like I did, you'll want to heed the following:

Note: If any of your packages doesn't have a release explicitly declared as D9-compatible (i.e. you are relying on a patch to make it ready), you will likely run into a dependency error when trying to update your codebase. To get around this, you can add an alias to drupal/core, such as:

composer require "drupal/core:9.0.0 as 8.9.0" --no-update && composer update

This was the only way forward for me. It's worth noting that I hit PHP memory limits with this command, though. You may need to run it like this (or update your php.ini file):

$ php -d memory_limit=3G /usr/local/bin/composer require "drupal/core:9.0.0 as 8.9.0" --no-update
$ php -d memory_limit=3G /usr/local/bin/composer update

//note that /usr/local/bin/composer can be replaced with 
//whichever path you use for your composer installation
//if you don't know where composer is installed, you 
//should be able to find the install path on Ubuntu with:
$ which composer

That should be that as far as the actual upgrade is concerned.

The next area of concern is running the database update after the upgrade. Upon running drush updb, I immediately got the following:

a configuration error in settings.php
hmm... I didn't expect that...

I have no idea where the FileStorageFactory.php file is coming from, but it looks like Drush isn't finding my sync directory. That's usually declared in settings.php. This actually took more than a minute to figure out, though. Upon looking at my settings.php, it looked like the sync directory was properly declared. It looks, however, as though this is actually a Drupal 9/PHP Syntax error. The way we declare the sync directory for D8 and D9 looks to require different syntax. It's not that the sync directory isn't defined--it's rather that the sync directory isn't defined using the variable in that error. Here's a side-by-side:

//Here's how we tell Drupal where the sync directory is in D8
$config_directories['sync'] = 'sites/default/files/config_blahblahblah/sync';

//And, here's how we need to tell Drupal where the sync directory is in D9
$settings['config_sync_directory'] = 'sites/default/files/config_blahblahblah/sync';

So, if you get this error, you'll want to update your settings.php accordingly.

Coming back to the database update, you'll likely hit one more error:

incompatible module error
Duhhhhhh... ...still not quite there...

So the Upgrade Status module that helps you attain Drupal 9 compatibility is not itself compatible with Drupal 9? I don't know how that makes sense, but who cares? I uninstalled the module with Drush and sure enough I was able to update the database.

These were the only hiccups I hit with the actual upgrade. 

All that's left after this is to get the branch ready for production.

Step 6: Prepping to Move D9 to DEV

Before I move the branch into DEV I'll likely need to bring the branch onto my dedicated localhost. My primary concern is that Composer and Drush get setup correctly. I expect that when I bring down a copy of my production database I'll hit a few hiccups with module settings, but other than that I don't expect too much trouble. I'd prefer not to put the branch into DEV until we're committed to going live with upgrade. In the meantime, my work computer will be a good place to do some thorough proofing and ensure that everything is working the way it's supposed to. It'll also give me a good idea of what to expect when I move the branch to DEV and later PROD

Step 7: Moving to PROD

I don't foresee any trouble here. I may need to come back to this post at a latter time and update, though. If everything goes right with moving the branch through our environments, this shouldn't be a big event.

After-thoughts - 6 Months Later

A couple more notes now that I've been running D9 for a bit:

  1. If I had to do it again, I wouldn't have used XAMPP on my VM. XAMPP is, I think, the faster method for getting a local server up and running. However, the headaches of getting Composer and Drush to play nice with XAMPP mean that, in the end, it's probably easier to install Apache2, MariaDB, PHP and PHPmyAdmin yourself. That can be a headache for anyone who doesn't have a stomach for DevOps, but I think it's justified. For my update to Drupal 9.1, I went with this method on a Lubuntu VM; Drush and Composer have been much smoother sailing.
  2. There are still a lot of modules that aren't ready for the latest versions of Drupal core. This seems problematic for anyone who wants to stay on top of security updates with Drupal 9. I haven't tested yet, but I believe you should be able to get around it by once again aliasing Drupal core with Composer, i.e., composer require "drupal/core:9.1.0 as 8.9.0" --no-update && composer update. It seems irritating that this is the only way to move forward with updates. I'm not trying to put the onus on module developers, by any means. It just seems disappointing that there couldn't have been a more intuitive path forward with D9. How long will we need to use aliases like this? Was last September really the right time to move to D9?