The power of CLI in Drupal development
Imagine you’re managing a news website with thousands of articles. One morning, your editor asks, “How many ‘breaking news’ articles do we have?”
Without a custom Drush command, you’d log into the admin UI, filter the content list, and count manually tedious process.
But with a custom command, you simply type:
…and get an answer in seconds!
This is the magic of Drush: transforming time-consuming tasks into instant insights. In this blog, we’ll walk through creating and refining custom Drush commands, showing how they can become indispensable tools in your Drupal workflow.
Why custom drush commands matter
Drush isn’t just a shortcut’s a command-line interface that lets you interact with Drupal at its core. Custom commands extend this power, letting you automate workflows, query data, and manage your site without touching a browser.
Real-world impact
Here’s how Drush can change your workflow:
Building blocks of a custom drush command
Let’s start with a concrete example: a command that counts nodes. This will illustrate the key components and decisions involved in building custom commands.
Project structure
This structure follows Drupal’s conventions, ensuring your command is discoverable and maintainable.
Module information file
This metadata tells Drupal what your module does and which versions it supports.
Services configuration
Here, you’re defining a service that Drush can recognise. The @entity_type.manager argument gives your command access to Drupal’s entity system.
Learn more about services in Drupal
The command implementation
Let’s look at the code for a custom node-count command, with full validation and helpful output.
How it works
This command uses Drupal’s entity query system to count nodes, varying the result based on the --type option. The entity_type.manager service provides access to this system, making the command reusable and testable.
Official Drush Command Authoring Docs
Integrating into existing modules
You don’t always need a new module. Adding commands to existing ones keeps your codebase clean.
Steps to integrate
This approach avoids bloating your project with unnecessary modules while keeping code organised.
Drupal 10 and 11: modernising your command
As Drupal evolves, so should your commands. Here’s how you can update the same command for Drupal 10/11 using modern PHP features.
Key improvements
These changes reflect Drupal’s shift toward stricter type safety and modern PHP practices.
Real-world example: content audit command
Scenario
A content agency migrates 50,000 articles from a legacy CMS. They need to verify data integrity:
Solution: a custom drush command
Why it works
This command leverages Drupal’s entity system to audit taxonomy terms, ensuring the migration team gets immediate feedback on taxonomy field integrity.
Best practices for custom commands
1. Use dependency injection
Injecting services like entity_type.manager makes your command testable and flexible.
Learn more about Dependency Injection in Drupal
2. Provide clear descriptions
Use the @usage annotation to document how users should run the command.
3. Handle edge cases
What happens if a node type doesn’t exist? Add validation:
This ensures your command fails gracefully instead of returning cryptic errors.
Common pitfalls and how to avoid them
Pitfall 1: Missing service tags
Forgetting to add drush.command in services.yml means Drush won’t recognise your command.
Pitfall 2: Overlooking access checks
Using accessCheck(true) ensures the command respects user permissions. Skipping it might expose sensitive data.
Pitfall 3: Hardcoding dependencies
Never hardcode services like \Drupal::entityTypeManager(). Always inject them for better testability.
Troubleshooting: When things go wrong
Case study: missing command after enabling the module
Symptoms: drush list doesn’t show your command.
Diagnosis:
Case study: slow query on large sites
Symptoms: The command takes 10+ seconds to count nodes.
Fix: Add caching:
This adds caching to prevent redundant queries during frequent audits.
Expanding the possibilities: beyond node counting
Custom commands aren’t limited to counting nodes. Let’s explore advanced use cases:
Use case 1: bulk entity updates
A real estate platform uses a command to update property listings when market data changes:
Use case 2: health checks
A healthcare site runs nightly health checks to ensure critical content is up-to-date:
Best practices in action
1. Meaningful aliases
Instead of custom:node-count, use nc for brevity.
2. Usage examples
Always include @usage annotations. For instance:
3. Help text
Describe what the command does in plain language:
Conclusion
Custom Drush commands, when thoughtfully built, do more than automate tasks—they shape a cleaner, faster, and more predictable development workflow.
By applying best practices like dependency injection, validation, and clear documentation, developers create commands that are easy to maintain and trusted across teams.
Over time, these tools become integral to managing complexity, improving deployment confidence, and making Drupal development feel less like firefighting and more like engineering.
Ready to go further? Explore the official Drush command authoring docs and Drupal’s services and dependency injection guide to keep levelling up your CLI skills!
Happy Drushing!