Drupal Contribution Environment: DDEV + the Workflow-Matched Add-on
When to Use
Use this when standing up a local environment for contribution work. The right add-on depends on which of the three workflows you are in.
Decision
| Add-on | For | Install command |
|---|---|---|
ddev/ddev-drupal-contrib (official) |
A single contrib module or theme | ddev add-on get ddev/ddev-drupal-contrib |
lussoluca/ddev-drupal-suite (community) |
Several interdependent contrib modules | ddev add-on get lussoluca/ddev-drupal-suite |
justafish/ddev-drupal-core-dev (community) |
Drupal core development | ddev get justafish/ddev-drupal-core-dev |
DDEV is the community standard — all drupal.org contribution docs and CI add-ons assume it.
Pattern
Contrib module/theme setup (ddev-drupal-contrib):
The key mental model: the module repo is the project root. web/ and vendor/ are generated by the add-on and .gitignore'd — never committed.
# 1. Clone the module repo (it IS the project root)
git clone git@git.drupalcode.org:project/my_module.git
cd my_module
# 2. Initialize DDEV
ddev config --project-type=drupal11 --docroot=web --php-version=8.3
# 3. Add the contrib add-on
ddev add-on get ddev/ddev-drupal-contrib
# 4. Start and install
ddev start
ddev poser # builds composer.contrib.json + installs Drupal into web/
ddev symlink-project # symlinks your module into web/modules/contrib/
# 5. Install Drupal
ddev drush si
Available commands after setup:
ddev phpcs
ddev phpstan
ddev phpunit web/modules/contrib/my_module/tests
ddev eslint
ddev stylelint
Switch core versions (multi-version testing):
# In .ddev/.env.web:
DRUPAL_CORE=^10
ddev restart # auto-selects compatible PHP version
ddev poser # rebuilds with the new core version
Core development setup (ddev-drupal-core-dev):
git clone git@git.drupalcode.org:project/drupal.git
cd drupal && git checkout main
ddev config --project-type=drupal11 --docroot=web
ddev get justafish/ddev-drupal-core-dev
ddev start && ddev drush si
ddev phpunit core/modules/<module>/tests
Do not install Drush into core with composer require — it pollutes core's composer.json.
Common Mistakes
- Wrong: Committing
web/orvendor/→ Right: These are generated; gitignore them - Wrong: Installing Drush into core with
composer require→ Right: Use the core-dev add-on's wrappers - Wrong: Not running
ddev poserafter switchingDRUPAL_CORE→ Right: The Drupal install must be rebuilt for the new version - Wrong: Using a global add-on config across projects with different core versions → Right: Set
DRUPAL_COREper project