Like a lot of other people in the Drupal community, I exclusively use DDEV for local development. I am regularly impressed by the breadth of features it offers out-of-the-box, and the add-on architecture means you can easily bring in additional capabilities as you need them. Recently, I even decided to vibe-code my own add-on to make it easy to run code validation checks and automated tests locally before pushing code. The working result has been transformative, allowing me to ship more code, with higher confidence, on more contrib projects.
One lingering point of friction for me has been the need to remember to prefix common tutorial commands with ddev for them to work as expected. I've been thinking about aliasing drush to ddev drush for some time, and I was even on a call with someone recently who mentioned that they always use a local setup with that in place.
So, what I'm about to share may already be common knowledge, but in the interest of making sure best practices are as easy to adopt as possible, I thought I would document the code I recently implemented that works to alias not only drush, but also composer, and the newer dr command added in Drupal core 11.4.
The fix
I decided that much like with the DDEV add-on, the most expedient path would be get an AI agent to make a recommendation. I wasn't disappointed. It came up with a Bash script that can be added to the bottom of your ~/.zshrc or ~/.bashrc file:
# Smart DDEV Wrappers for Drush, Composer, and the Drupal Core CLI (dr)
_ddev_smart_wrapper() {
local tool="$1"
shift
if ddev describe >/dev/null 2>&1; then
# If the tool is Drupal's new 'dr' CLI, execute it inside the container
if [ "$tool" = "dr" ]; then
ddev exec dr "$@"
else
ddev "$tool" "$@"
fi
else
# Fallback to host machine execution
if command -v "$tool" >/dev/null 2>&1; then
command "$tool" "$@"
# Special local fallback for 'dr' if it's in the project vendor bin directory
elif [ "$tool" = "dr" ] && [ -f "./vendor/bin/dr" ]; then
./vendor/bin/dr "$@"
else
echo "DDEV project not detected, and '$tool' is not available on your host machine."
return 1
fi
fi
}
# Register the functions
drush() { _ddev_smart_wrapper drush "$@"; }
composer() { _ddev_smart_wrapper composer "$@"; }
dr() { _ddev_smart_wrapper dr "$@"; }Some additional information it provided:
- Composer Safety: If you run
composer create-projectoutside of a DDEV directory, it gracefully falls back to your host machine's Composer so you can spin up new sites without issues. - The New
drCLI Integration: Because DDEV doesn't have a native, top-levelddev drcommand yet, the wrapper automatically routes it throughddev exec drwhen inside an active environment, matching the recommended Drupal core workflow. - DRY Code: Instead of repeating the
if/elseblock for every single tool, the_ddev_smart_wrapperhandles the heavy lifting, making it incredibly easy for you to add more tools in the future (likenpmorwp-cli) just by adding a new single-line function at the bottom.
Once you have the code added to the appropriate file, you can use the new, aliased commands by opening a new terminal window. Or, you can refresh the configuration used in the same window with:
source ~/.zshrc
# OR
source ~/.bashrcHappy coding!
Comments