Creating custom Drush 9 commands in Drupal 8

Creating Custom Drush 9 Commands in Drupal 8

In Drupal 8.4.X and later releases, Drush 9 is the only supported and recommended version. One of the key changes introduced in this version is a new model of writing custom Drush commands. From now on, .inc files are obsolete and you will no longer use them for your commands, which are now classes based on AnnotatedCommand format.

The underlying structure of a module containing your custom Drush command will look as follows:

Module structure with custom Drush 9 command file

Default information file with basic information for the module.


name: Drush 9 Custom Commands
description: Example of Drush 9 custom command.
core: 8.x
type: module
package: Examples file

Using the standard services.yml file will not work anymore, and it will lead to an error since Drush now expects you to use a separate file with service definitions for your custom Drush commands.


    class: \Drupal\drush9_custom_commands\Commands\Drush9CustomCommands
      - { name: drush.command }


Drush9CustomCommands.php file

As such, this is the most crucial file, including the entire definition for your commands. 



namespace Drupal\drush9_custom_commands\Commands;

use Drush\Commands\DrushCommands;

 * A drush command file.
 * @package Drupal\drush9_custom_commands\Commands
class Drush9CustomCommands extends DrushCommands {

   * Drush command that displays the given text.
   * @param string $text
   *   Argument with message to be displayed.
   * @command drush9_custom_commands:message
   * @aliases d9-message d9-msg
   * @option uppercase
   *   Uppercase the message.
   * @option reverse
   *   Reverse the message.
   * @usage drush9_custom_commands:message --uppercase --reverse drupal8
  public function message($text = 'Hello world!', $options = ['uppercase' => FALSE, 'reverse' => FALSE]) {
    if ($options['uppercase']) {
      $text = strtoupper($text);
    if ($options['reverse']) {
      $text = strrev($text);


Your commands class inherits from DrushCommands, and you can use it to include numerous commands, of which all are separate methods using annotations.

Some of the annotations available for use include:
@command – command definition, which needs to follow the module: command structure;
@aliases – aliases for your commands, separated with spaces;
@param – which defines the input parameters for your command;
@option – which defines the options available for your commands, which should be put in an associative array, where the name of the option is the key;
@usage – example showing how the command should be used.

Usage examples for the above command:

Drush d9-message 
Hello world!

drush d9-message --uppercase --reverse drupal8



At our Drupal agency, we are pretty sure that those who wrote their custom Drush commands before Drush 9 was released can notice quite a number of differences here, as we’re seeing a departure from the old way, which was well-known to Drupal 7 developers, towards the new Symphony-based solution. Those who haven’t had a chance to work with Drush commands yet will probably find the above example pretty boring. What can your custom Drush command be used for in practice? For example, recently I had an opportunity to integrate Drupal with an external blogging service. Using cron, the posts are added to Drupal at specified intervals. Thanks to a custom Drush command, I can run such an operation at any time without using UI. What is more, the parameter enables its user to download any number of posts using a numeric value or “all” setting. The above solution proved to be very useful during the initial migration when all the existing posts and entries had to be downloaded. What kind of processes are you going to make easier thanks to custom Drush commands?

3. Best practices for software development teams