Drupal 9 Upgrade: Composer and Drupal's Module Directory

It seems like a no-brainer to me, but I must have missed something. Why Drush, Drupal's admin UI and Composer would install modules into different directories by default is beyond me.

Default Module Directory

Where are modules really supposed to go, anyways? Here's what Drupal.org has to say:

Drupal will look for modules in a few different locations; The root /modules directory (preferred), or any /sites/*/modules directory. Within these locations, Drupal will recurse through all subdirectories looking for modules. A common practice is to add all modules downloaded from Drupal.org to /modules/contrib. And all modules containing custom project-specific code to /modules/custom.

The preferred method is to put them into the /modules directory. Beyond that, though, it looks as though how and whether you'd like to organize your modules into sub-directories is really up to personal preference. So, why,  then, would the various install methods differ in install location? If you install a module from either Drush 8 or Drupal's admin UI, by default, the module will go into root/modules; on the other hand, if you install with Composer it'll go into root/modules/contrib. Big deal?--under normal circumstances, perhaps not.

Side note: I haven't actually installed via the admin UI in quite a while... so not 100% on where it installs to; if my memory is correct, though, it's never gone to root/modules/contrib

What if, however, you've got a D8 site that has been setup exclusively with Drush 8, and now you're moving to Drupal 9 which isn't compatible with Drush 8. I lamented in my last D9 post that pm:updatestatus has been removed from Drush 10 in favor of moving module updates to Composer. I lament it again. It's not the end of the world, but it's just one more headache to deal with. Let's say I have the Search404 module in my D8 project and it needs to be updated to a D9 compatible version. If I run...

$ composer require 'drupal/search404:^2.0'
//or actually,  this, because I know we'll hit a PHP memory limit with it...
$ php -d memory_limit=3G /usr/local/bin/composer require 'drupal/search404:^2.0'

...Composer will ignore the existing Search404 module (the one under root/modules) altogether and install the newest module version into the contrib sub-directory. Better yet, Drupal doesn't even seem to find the newer version. After resetting some commits and worrying that I'd need to migrate the module from one folder to another (and somehow migrate config settings within the DB), it turns out all you need to do is read the instructions Drupal.org has for module installs with Composer.

If you want to change the locations in the file system where packages are installed, you can modify the "installer-paths" section of the composer.json file. This also can be useful if you need to have specific packages installed in their own locations.

From the root of your drupal project, you'll want to open up the composer.json file and remove the contrib sub-directory from the installer path:

changing the installer-path in composer.json file
I have a feeling I'll need to remove the contrib sub-directory from most of these installer-paths; it's just not the way this project is set up.

Save and you should be good to run that composer require again.

Like I said--not the end of the world. Still, it seems counter intuitive that the Drupal admin UI, Drush and Composer would default to different locations for module installs/updates.

Drush seems like an afterthought at this point. It makes me worry that at some point the admin UI will share that destiny. This headache serves as a reminder that so much of DevOps is less about code-fu and more about attention to detail--at a granular level. If you don't read the documentation from start to finish, you can expect turbulence.