drush

SKILL.md

Drush CLI Reference

Command-line interface for Drupal site management. Drush runs in the Drupal bootstrap context, giving full access to the Drupal API.

Command Structure

All commands follow: drush <command> [arguments] [--options]

Most commands have short aliases. Use drush list to see all available commands, drush <command> --help for details.

In DDEV: Prefix with ddev (e.g., ddev drush cr).

Quick Reference

Task Command Alias
Cache rebuild drush cache:rebuild drush cr
Config export drush config:export drush cex
Config import drush config:import drush cim
Config get drush config:get <name> drush cget <name>
Config set drush config:set <name> <key> <value> drush cset <name> <key> <value>
Database update drush updatedb drush updb
Module install drush pm:install <module> drush en <module>
Module uninstall drush pm:uninstall <module> drush pmu <module>
List modules drush pm:list drush pml
User login link drush user:login drush uli
User info drush user:information <name>
Watchdog logs drush watchdog:show drush ws (requires dblog module)
Status overview drush status drush st
Run cron drush cron
State get drush state:get <key> drush sget <key>
State set drush state:set <key> <value> drush sset <key> <value>
Deploy (updb+cim+cr) drush deploy
Code generation drush generate drush gen
Site requirements drush core:requirements drush rq
Watchdog tail drush watchdog:tail drush wt (requires dblog module)
Queue list drush queue:list
Queue run drush queue:run <name>

Running PHP Code

Drush can evaluate arbitrary PHP within full Drupal bootstrap context.

Inline PHP with eval

# Simple expression
drush php:eval "echo \Drupal::VERSION;"

# Load and inspect an entity
drush php:eval "\$node = \Drupal\node\Entity\Node::load(1); echo \$node->getTitle();"

# Query entities
drush php:eval "\$ids = \Drupal::entityTypeManager()->getStorage('node')->getQuery()->accessCheck(FALSE)->condition('type', 'article')->range(0, 5)->execute(); print_r(\$ids);"

# Access a service
drush php:eval "echo \Drupal::service('extension.list.module')->getPath('node');"

# Get current user
drush php:eval "echo \Drupal::currentUser()->getAccountName();"

Shell escaping: Use single quotes around the PHP string in fish/zsh to avoid $ expansion, or escape \$ in double quotes.

Interactive PHP shell

# Opens interactive REPL with Drupal bootstrapped
drush php:cli

Useful for exploring APIs interactively. Tab completion available for classes/functions.

Running PHP scripts

# Execute a PHP file with full Drupal bootstrap
drush php:script path/to/script.php

# Pass arguments (available as $extra in the script)
drush php:script path/to/script.php -- arg1 arg2

Executing SQL Commands

Direct SQL queries

# Run a SQL query directly
drush sql:query "SELECT nid, title FROM node_field_data LIMIT 10"

# Count content by type
drush sql:query "SELECT type, COUNT(*) as count FROM node_field_data GROUP BY type"

# Check a specific table (MySQL-specific syntax)
drush sql:query "DESCRIBE users_field_data"

# Show tables matching a pattern (MySQL-specific)
drush sql:query "SHOW TABLES LIKE '%node%'"

Note: DESCRIBE and SHOW TABLES are MySQL-specific. For PostgreSQL use \d table_name in sql:cli.

Database shell and dumps

# Open interactive database client (mysql/psql)
drush sql:cli

# Create database dump
drush sql:dump > dump.sql
drush sql:dump --result-file=/tmp/dump.sql
drush sql:dump --gzip --result-file=/tmp/dump.sql  # produces dump.sql.gz

# Import SQL file
drush sql:cli < dump.sql

# Show database connection info
drush sql:conf

# Sanitize user data (emails, passwords) for safe copies
drush sql:sanitize

# Drop all tables (use with caution)
drush sql:drop

Retrieving Configuration

Get configuration values

# Get entire config object (YAML output)
drush config:get system.site
drush cget system.site

# Get a specific key
drush config:get system.site name
drush cget system.site page.front

# List all config names (no config:list command in Drush 13+)
drush php:eval 'foreach (\Drupal::service("config.storage")->listAll("system") as $name) echo "$name\n";'

# Get active vs sync diff
drush config:status

Edit and set configuration

# Set a single value
drush config:set system.site name "My Site"
drush cset system.site name "My Site"

# Set nested value
drush config:set system.site page.front "/node"

# Edit full config object in editor
drush config:edit system.site

# Delete a config object
drush config:delete <config-name>

Config export/import workflow

# Export active config to sync directory
drush cex

# Show pending changes (what would be imported)
drush config:status

# Import config from sync directory
drush cim

# Import partial (only imports items in sync dir, does not delete active-only config)
drush cim --partial

# Import from a non-default directory
drush cim --source=/path/to/config

# Export single config item to stdout
drush config:get system.site --format=yaml

Module Management

# List all modules with status
drush pml
drush pml --status=enabled
drush pml --type=module --status="not installed"

# Install module(s)
drush en module_name
drush en module_one module_two

# Uninstall module(s)
drush pmu module_name

# Check if module is enabled
drush pml --filter=module_name

User Management

# Generate one-time login link
drush uli
drush uli --uid=1
drush uli admin

# Create user
drush user:create username --mail="user@example.com" --password="pass"

# Add role to user
drush user:role:add editor admin

# Remove role
drush user:role:remove editor admin

# Block/unblock user
drush user:block username
drush user:unblock username

# Reset password
drush user:password admin "newpassword"

Roles and Permissions

Inspecting roles

# List all roles with their permissions
drush role:list
drush role:list --format=table
drush role:list --format=json

# Get permissions for a specific role via config
drush cget user.role.editor

# Check a user's roles
drush user:information admin --format=json

Checking permissions

# List all available permissions (grep to search)
drush php:eval 'echo implode("\n", array_keys(\Drupal::service("user.permissions")->getPermissions()));'

# Search for specific permissions
drush php:eval 'echo implode("\n", array_keys(\Drupal::service("user.permissions")->getPermissions()));' | grep administer

Managing permissions

# Grant permission to a role
drush role:perm:add anonymous 'access content'

# Grant multiple permissions
drush role:perm:add editor 'access content,administer nodes'

# Remove permission from a role
drush role:perm:remove anonymous 'access content'

# Create / delete a role
drush role:create editor Editor
drush role:delete editor

Code Generation

Drush includes scaffolding for modules, plugins, forms, entities, and more via drush generate (powered by drupal-code-generator).

# Interactive: pick a generator from the list
drush generate

# Generate a specific component
drush generate module
drush generate controller
drush generate form:config
drush generate plugin:block
drush generate entity:content
drush generate hook

# Preview what would be generated (no files written)
drush generate controller --dry-run

# Pre-fill answers to skip interactive prompts
drush generate controller --answer=Example --answer=example

# See all available generators
drush generate --dry-run

Common generators: module, controller, field, hook, form:simple, form:config, form:confirm, plugin:block, plugin:action, entity:content, entity:configuration, service-provider, drush:command.

Run drush generate <name> --help for details on a specific generator.

Useful Options

Option Description
--format=json JSON output (useful for scripting/parsing)
--format=yaml YAML output
--format=table Table output (default for many commands)
-y Auto-confirm prompts
-v Verbose output
--debug Debug output
--uri=http://example.com Set base URI for commands
--root=/path/to/drupal Set Drupal root

Deprecated and Removed Commands

Commands that NO LONGER EXIST in modern Drush (12+). Do NOT suggest these:

Removed Command What to Use Instead
drush entity-updates / drush entup Removed entirely. Entity schema updates are handled by drush updatedb (drush updb). If hook_update_N does not cover your change, write a custom update hook.
drush pm-download / drush dl Use composer require drupal/<module>
drush pm-update / drush up Use composer update then drush updb
drush pm-enable (old syntax) Use drush pm:install / drush en
drush pm-disable / drush dis Use drush pm:uninstall / drush pmu (no "disable" concept in modern Drupal)
drush features-* Features module commands; use config management instead
drush sql-sync Still exists as sql:sync but requires site aliases. Without aliases, use drush sql:dump + transfer, or tools like phabalicious copy-from
drush core-rsync Still exists as core:rsync but requires site aliases. Without aliases, use rsync directly or deployment tools
drush registry-rebuild / drush rr Removed. Use drush cr instead
drush variable-get/set Variables replaced by State API (drush sget/drush sset) or Config API (drush cget/drush cset)

General rule: If a command uses a hyphen (e.g., entity-updates), it is likely old Drush syntax. Modern Drush uses colons (e.g., cache:rebuild).

Common Mistakes

Wrong Right Why
drush entity-updates drush updb entity-updates removed in Drush 11+
drush dl module composer require drupal/module Package management via Composer now
drush up composer update && drush updb Updates via Composer, then run DB updates
drush dis module drush pmu module No disable concept; uninstall instead
drush cim without drush cr after issues drush cr && drush cim Cache rebuild can resolve import errors
drush variable-get x drush sget x or drush cget x Variables removed; use State or Config API
Running drush cim before drush updb drush updb && drush cim or drush deploy Update hooks may add schemas needed by config import
Manual drush updb && drush cim && drush cr drush deploy deploy handles correct order and error handling
drush cim/drush updb in scripts without -y Add -y flag These commands prompt for confirmation and hang without it
Forgetting accessCheck(FALSE) in entity queries via php:eval Always add ->accessCheck(FALSE) Required since Drupal 9.2, throws deprecation without it
Weekly Installs
4
GitHub Stars
1
First Seen
6 days ago
Installed on
opencode4
gemini-cli4
claude-code4
github-copilot4
codex4
amp4