Auto discovery of global commands in Drush

Matt Glaman
3 min readJan 23, 2022

This blog post is about the auto-discovery of global Drush commands. To be honest, I have no idea what a global command is or means and how it differentiates between a site command. However, I find the global-command discovery feature fascinating and a streamlined developer experience when writing commands for your Drupal site. Note: this feature is available in Drush 10.5+ or 11.0+.

Some Drush commands can already be auto-discovered. Those are site-wide commands. Site-wide Drush commands exist in your Drupal codebase’s drush/Commands directory and use the Drush\Commands namespace.

I am working on a new Drupal book and dove into a section that discussed writing Drush commands for your Drupal module. While Drush provides a command to generate Drush commands, I wanted to brush up on the manual steps and help explain the generated code. That’s when I saw the section on auto-discovered commands.

Drush global commands can be auto-discovered if they meet the following conditions:

  • The command is in a class that is PSR-4 auto-loadable
  • The namespace for the command class contains Drush\Commands. So App\Drush\Commands would be a viable namespace.
  • The command class ends with DrushCommands. So the filename would be AppDrushCommands or FooDrushCommands, etc.

Personal note: I find the file naming requirement a bit redundant since we already have a specific namespace, and the class is inspected to ensure it isn’t abstract, an interface, and is a subclass of Drush\Commands\DrushCommands.

This is accomplished with Robo\ClassDiscovery\RelativeNamespaceDiscovery. The relative namespace discovery class inspects the known namespaces in the class autoload. Given an expected relative namespace (Drush\Commands) and a file matching pattern (*DrushCommands.php), it will return available classes that have been discovered.

Here is a copy of the code from Drush (Application.php#L393-L407):

/**
* Discovers commands that are PSR4 auto-loaded.
*/
protected function discoverPsr4Commands(ClassLoader $classLoader): array
{
$classes = (new RelativeNamespaceDiscovery($classLoader))
->setRelativeNamespace('Drush\Commands')
->setSearchPattern('/.*DrushCommands\.php$/')
->getClasses();

return array_filter($classes, function (string $class): bool {
Matt Glaman

Open source developer, working with Drupal and building Drupal Commerce.