Skip to content

Custom (Shell) Commands

It's quite easy to add custom commands to ddev; they can execute either on the host or in the various containers. The basic idea is to add a bash script to either the specific project in .ddev/commands/host or .ddev/commands/<containername> or globally for every project in ~/.ddev/commands

There are example commands provided in ddev/commands/*/*.example that can just be copied or moved (or symlinked) and used as commands. For example, .ddev/commands/host/mysqlworkbench.example can be used to add a "ddev mysqlworkbench" command, just change it from "mysqlworkbench.example" to "mysqlworkbench". If you're on macOS or Linux (or some configurations of Windows) you can just cd .ddev/commands/host && ln -s mysqlworkbench.example mysqlworkbench. Also, a new ddev mysql command has been added using this technique (as a db container command). Also see the ddev mysql command.

Notes for all command types

  • The command filename is not what determines the name of the command. That comes from the Usage doc line (## Usage: commandname).
  • To confirm that your custom command is available, run ddev -h, and look for it in the list.

Host commands

To provide host commands, place a bash script in .ddev/commands/host. For example, a PhpStorm launcher to make the ddev PhpStorm command might go in .ddev/commands/host/phpstorm` with these contents:

#!/usr/bin/env bash

## Description: Open PhpStorm with the current project
## Usage: phpstorm
## Example: "ddev phpstorm"

# Example is macOS-specific, but easy to adapt to any OS
open -a PhpStorm.app ${DDEV_APPROOT}

Container commands

To provide a command which will execute in a container, add a bash script to .ddev/commands/<container_name>, for example, .ddev/commands/web/mycommand. The bash script will be executed inside the named container. For example, see the several standard ddev script-based web container commands,

In addition to commands that run in the standard ddev containers like "web" and "db", you can run commands in custom containers, just using the service name, like .ddev/commands/solr/<command>. Note, however, that your service must mount /mnt/ddev_config as the web and db containers do, so the volumes section of docker-compose.<servicename>.yaml needs:

    volumes:
    - ".:/mnt/ddev_config"

For example, to add a solrtail command that runs in a solr service, add .ddev/commands/solr/solrtail with:

#!/bin/bash

## Description: Tail the main solr log
## Usage: solrtail
## Example: ddev solrtail

tail -f /opt/solr/server/logs/solr.log

Global commands

Global commands work exactly the same as project-level commands, you just have to put them in your global .ddev directory. Your home directory has a .ddev/commands in it; there you can add host or web or db commands.

Shell Command Examples

There are many examples of global and project-level custom/shell commands that are provided directly by DDEV, and you can adapt these to your use. They can be found in your ~/.ddev/commands/* directories and in your project's .ddev/commands/* directories. There you'll see how to provide usage, examples, and how to use arguments provided to the commands. For example, the xdebug command shows simple argument processing and the launch command demonstrates flag processing.

Environment variables provided

A number of environment variables are provided to the script. These are generally supported, but please avoid using undocumented environment variables. Useful variables for host scripts are:

  • DDEV_APPROOT: file system location of the project on the host
  • DDEV_DATABASE: database in use, in format type:version, for example mariadb:10.5.
  • DDEV_DOCROOT: Relative path from approot to docroot
  • DDEV_HOSTNAME: Comma-separated list of FQDN hostnames
  • DDEV_HOST_DB_PORT: Localhost port of the database server
  • DDEV_HOST_HTTPS_PORT: Localhost port for https on webserver
  • DDEV_HOST_WEBSERVER_PORT: Localhost port of the webserver
  • DDEV_PHP_VERSION: PHP version running
  • DDEV_PRIMARY_URL: Primary URL for the project
  • DDEV_PROJECT: Project name, like "d8composer"
  • DDEV_PROJECT_TYPE: drupal8, typo3, backdrop, wordpress, etc.
  • DDEV_ROUTER_HTTP_PORT: Router port for http
  • DDEV_ROUTER_HTTPS_PORT: Router port for https
  • DDEV_SITENAME: Project name, like "d8composer".
  • DDEV_TLD: Top-level domain of project, like "ddev.site"
  • DDEV_WEBSERVER_TYPE: nginx-fpm, apache-fpm`
  • GOARCH: architecture: "arm64", "amd64"
  • GOOS: operating system: "windows", "darwin", "linux"

Useful variables for container scripts are:

  • DDEV_DOCROOT: Relative path from approot to docroot
  • DDEV_FILES_DIR: Directory of user-uploaded files
  • DDEV_HOSTNAME: Comma-separated list of FQDN hostnames
  • DDEV_PHP_VERSION: PHP version running
  • DDEV_PRIMARY_URL: Primary URL for the project
  • DDEV_PROJECT: Project name, like "d8composer"
  • DDEV_PROJECT_TYPE: drupal8, typo3, backdrop, wordpress, etc.
  • DDEV_ROUTER_HTTP_PORT: Router port for http
  • DDEV_ROUTER_HTTPS_PORT: Router port for https
  • DDEV_SITENAME: Project name, like "d8composer".
  • DDEV_TLD: Top-level domain of project, like "ddev.site"
  • DDEV_WEBSERVER_TYPE: nginx-fpm, apache-fpm
  • IS_DDEV_PROJECT: if set to "true" it means that php is running under DDEV

Annotations supported

The custom commands support various annotations in the header which are used to provide additional information about the command to the user.

"Description" annotation

Description is used for the listing of available commands and for the help message of the custom command.

Usage: ## Description: <command-description> Example: ## Description: my great custom command

"Usage" annotation

Usage is used for the help message to provide an idea to the user how to use this command.

Usage: ## Usage: <command-usage> Example: ## Usage: commandname [flags] [args]

"Example" annotation

Example is used for the help message to provide some usage examples to the user. Use \n to force a line break.

Usage: ## Example: <command-example> Example: ## Example: commandname\ncommandname -h

"Flags" annotation

Flags is used for the help message. All defined flags here are listed with their shorthand if available. It has to be encoded according the following definition:

Usage: ## Flags: <json-definition>

This is the minimal usage of a flags definition:

Example: ## Flags: [{"Name":"flag","Usage":"sets the flag option"}] Output:

Flags:
  -h, --help          help for ddev
  -f, --flag          sets the flag option

Multiple flags are separated by a comma:

Example: ## Flags: [{"Name":"flag1","Shorthand":"f","Usage":"flag1 usage"},{"Name":"flag2","Usage":"flag2 usage"}] Output:

Flags:
  -h, --help          help for ddev
  -f, --flag1         flag1 usage
      --flag2         flag2 usage

The following fields can be used for a flag definition:

  • Name: the name as it appears on command line
  • Shorthand: one-letter abbreviated flag
  • Usage: help message
  • Type: possible values are bool, string, int, uint (defaults to bool)
  • DefValue: default value for usage message
  • NoOptDefVal: default value, if the flag is on the command line without any options
  • Annotations: used by cobra.Command bash autocomplete code see https://github.com/spf13/cobra/blob/master/bash_completions.md

"ProjectTypes" annotation

If your command should only be visible for a particular project type, ProjectTypes will allow you to define the supported types. This is especially useful for global custom commands. See https://ddev.readthedocs.io/en/stable/users/cli-usage/#quickstart-guides for more information about the supported project types. Multiple types are separated by a comma.

Usage: ## ProjectTypes: <list-of-project-types> Example: ## ProjectTypes: drupal7,drupal8,drupal9,backdrop

"OSTypes" annotation (host commands only)

If your host command should only run on one or more operating systems, add the OSTypes annotation. Multiple types are separated by a comma. Valid types are:

  • darwin for macOS
  • windows for Windows
  • linux for Linux

Usage: ## OSTypes: <list-of-os-types> Example: ## OSTypes: darwin,linux

"HostBinaryExists" annotation (host commands only)

If your host command should only run if a particular file exists, add the HostBinaryExists annotation.

Usage: ## HostBinaryExists: <path/to/file> Example: ## HostBinaryExists: /Applications/Sequel ace.app

"DBTypes" annotation

if your command should only be available for a particular database type, add the DBTypes annotation. Multiple types are separated by a comma. Valid types the available database types.

Usage: ## DBTypes: <type> Example: ## DBTypes: postgres

Known Windows OS issues

  • Line Endings: If you are editing a custom command which will run in a container, it must have LF line endings (not traditional Windows CRLF line endings). Remember that a custom command in a container is a script that must execute in a Linux environment.
  • If ddev can't find "bash" to execute it, then the commands can't be used. If you are running inside git-bash in most any terminal, this shouldn't be an issue, and ddev should be able to find git-bash if it's in C:\Program Files\Git\bin as well. But if neither of those is true, add the directory of bash.exe to your PATH environment variable.

Last update: July 7, 2022