Alias Your Local DDEV Commands

By mandclu , Thu, 07/02/2026 - 01:19

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-project outside 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 dr CLI Integration: Because DDEV doesn't have a native, top-level ddev dr command yet, the wrapper automatically routes it through ddev exec dr when inside an active environment, matching the recommended Drupal core workflow.
  • DRY Code: Instead of repeating the if/else block for every single tool, the _ddev_smart_wrapper handles the heavy lifting, making it incredibly easy for you to add more tools in the future (like npm or wp-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 ~/.bashrc

Now, you can run commands within DDEV that work as expected, even if you forget to use the ddev prefix. For example:

composer require drupal/events_calendar
dr recipe ../recipes/events_calendar
drush cr

Happy site building!

Tags

Comments

Restricted HTML

  • Allowed HTML tags: <a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • Lines and paragraphs break automatically.
  • Web page addresses and email addresses turn into links automatically.