drupal-ddev
Skill81 starsChanged 42 days agoMITView on GitHub
Provides DDEV local development patterns for Drupal - ddev commands, .ddev/config.yaml, database import/export and snapshots, Drush and Composer through ddev, Xdebug, local Solr, Mutagen performance, and recovery from Docker, Mutagen and router failures. Use when running ddev start/restart/exec/drush/composer, editing .ddev/config.yaml, importing or snapshotting a database, debugging slow or hung DDEV containers, or recovering a local environment after a Docker crash.
In this repository25 other files it gives its agents.
- AGENTS.mdAGENTS.md
- CLAUDE.mdCLAUDE.md
- acquia-sourceSkill
- canvas-contributionSkill
- claude-code-mcp-setupSkill
- design-reviewSkill
- drupal-api-endpointsSkill
- drupal-at-your-fingertipsSkill
- drupal-canvas-sdcSkill
- drupal-canvasSkill
- drupal-config-mgmtSkill
- drupal-config-reconcileSkill
- drupal-contrib-mgmtSkill
- drupal-deploy-safetySkill
- drupal-mailSkill
- drupal-performanceSkill
- drupal-search-apiSkill
- drupal-simple-oauthSkill
- drupal-testingSkill
- drupal-views-patternsSkill
- drupal-vite-themeSkill
- ivangrynenko-cursorrules-drupalSkill
- mockup-paritySkill
- sentry-integrationSkill
- skill-developerSkill
The file
We split this skill into the rules it gives an agent
7 rules. About 0 are common, 5 are distinctive, and 2 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈5
Distinctive · estimate
This author's own choices. Worth a look.
2
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 45
Read the matching file when the task needs that detail.
- Distinctive: line 132
Use ddev composer: instead of local composer
- Distinctive: line 200
If you're seeing PHP deprecation warnings when running Drush commands (especially with PHP 8.4), create a custom PHP configuration file to …
- Very specific: line 255
Run long drush operations (updb on a big upgrade, cold cr) ONCE, in the background, with a generous timeout — do not fire repeated shorter …
- Distinctive: line 312
If Docker Desktop gets into a bad state producing overlay2 or containerd I/O errors such as:
- Distinctive: line 331
After Docker crashes or force-quits, DDEV can get into a bad state where:
- Very specific: line 346
If ddev poweroff doesn't resolve it:
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
DDEV for Drupal Development
Comprehensive patterns for using DDEV as your local Drupal development environment, including setup, configuration, workflow optimization, and troubleshooting.
When This Skill Activates
Activates when working with DDEV local development including:
- DDEV configuration (.ddev/config.yaml)
- Local environment setup and management
- Database import/export operations
- Drush integration
- Xdebug and debugging tools
- Performance optimization
- Multi-site and custom commands
Available Topics
Core Setup
- @references/config-yaml.md - .ddev/config.yaml reference
- @references/workflows.md - New/imported project setup, remote DB sync, daily workflow, multi-project management
Database Operations
- @references/database.md - Import, export, and snapshot workflows
Development Tools
- @references/xdebug.md - Debugging with Xdebug
- @references/solr.md - Local Solr search setup
Advanced
- @references/custom-commands.md - Creating project-specific commands
- @references/performance.md - Optimizing DDEV performance
- @references/load-and-recovery.md - Host CPU saturation, post-crash recovery traps, trimming the Mutagen payload, Kernel tests on a throwaway DB, coordinating multiple agents on one project
See /references/ directory for complete documentation.
References
Read the matching file when the task needs that detail; the Common Issues section below stays here because it is needed on almost every use.
| File | Read it when |
| references/workflows.md | Setting up a new project, importing an existing one, syncing a database from a remote environment, following the daily start/stop routine, managing several DDEV projects, or cleaning up agent git worktree directories |
| references/performance.md | DDEV feels slow on macOS (Mutagen vs NFS), tuning MariaDB, or PHPUnit/Kernel runs are slow (fast bootstrap, smallest test scope, where to run Kernel suites) |
| references/xdebug.md | Turning Xdebug on/off or wiring an IDE (VSCode launch.json) to it |
| references/custom-commands.md | Writing a project-specific ddev <command> under .ddev/commands/web/ |
| references/config-yaml.md | Editing .ddev/config.yaml beyond the basic example below (PHP, database, ports, hostnames, hooks, services, env vars) |
| references/database.md | Importing, exporting, snapshotting, accessing or sanitizing the database, or a database import fails |
| references/solr.md | Running a local Solr service for Search API |
| references/load-and-recovery.md | Requests hang under heavy host load, after a Docker crash, trimming the Mutagen payload, running Kernel tests against a throwaway DB, or several agents share one DDEV project |
Quick Reference
Essential Commands
# Start project
ddev start
# Stop project
ddev stop
# Restart services
ddev restart
# SSH into web container
ddev ssh
# Run Drush commands
ddev drush cr
ddev drush status
ddev drush config:status
# Run Composer
ddev composer require drupal/module_name
ddev composer update
# Database operations
ddev import-db --file=backup.sql.gz
ddev export-db --file=backup.sql.gz
ddev snapshot
# View logs
ddev logs
ddev logs -f # Follow mode
# Describe project
ddev describe
# Access URLs
ddev launch # Open site in browserBasic .ddev/config.yaml
name: myproject
type: drupal11
docroot: web
php_version: "8.3"
webserver_type: nginx-fpm
database:
type: mariadb
version: "10.6"
nodejs_version: "24"
# Additional services
additional_services:
- solr
# Custom upload/execution limits
upload_dirs:
- web/sites/default/files
# Performance settings
performance_mode: mutagen # For macOSBest Practices
- Commit .ddev/config.yaml - Share config with team
- Use ddev composer instead of local composer
- Don't commit database snapshots - Too large
- Create snapshots before risky operations
- Disable Xdebug when not debugging - Performance impact
- Use mutagen on macOS - Much faster file sync
- Regular ddev poweroff - Free up system resources
- Version pin services - PHP, database, Node.js
- Use hooks for automation - Post-start tasks
- Document custom commands - Help team members
Common Issues
Site Not Loading
# Restart project
ddev restart
# Check status
ddev describe
# View logs
ddev logs
# Clear Drupal cache
ddev drush crDatabase Connection Error
# Check database is running
ddev describe
# Verify settings.php or settings.ddev.php exists
ddev ssh
ls web/sites/default/settings*.phpPort Conflicts
# Stop all DDEV projects
ddev poweroff
# Check for port conflicts
lsof -i :80 -i :443
# Change router HTTP port if needed
ddev config --router-http-port=8080 --router-https-port=8443Slow Performance on macOS
# Enable mutagen
ddev config --performance-mode=mutagen
ddev restart
# Or use NFS
ddev config --nfs-mount-enabled=true
ddev restartPHP Deprecation Warnings in Drush
If you're seeing PHP deprecation warnings when running Drush commands (especially with PHP 8.4), create a custom PHP configuration file to suppress them:
.ddev/php/drush.ini:
; Suppress PHP deprecation warnings for Drush commands
[PHP]
error_reporting = 22527
display_errors = Off
display_startup_errors = Off
log_errors = On
error_log = /tmp/php-errors.logThen restart DDEV:
ddev restartHow it works:
error_reporting = 22527equalsE_ALL & ~E_DEPRECATEDdisplay_errors = Offprevents warnings from appearing on STDERRdisplay_startup_errors = Offsuppresses bootstrap warnings- Errors are logged to
/tmp/php-errors.loginstead of being displayed
This configuration applies to both web and CLI contexts since DDEV copies .ddev/php/*.ini files to both /etc/php/[version]/cli/conf.d/ and /etc/php/[version]/fpm/conf.d/.
Interrupted ddev composer install Leaves Phantom-Installed Packages (Patches Never Applied)
If ddev composer install/update is killed mid-run (Docker OOM exit 137, host timeout, crash), Composer may have already recorded the package as installed before the kill — so the NEXT composer install reports "Nothing to install, update or remove" and composer-patches never applies that package's patches. The result is a half-materialized contrib tree that produces impossible-looking runtime errors (e.g. DI ServiceCircularReferenceExceptions, TypeErrors from an unpatched constructor) that do NOT reproduce once the tree is repaired.
Diagnose:
# Verify patch application (a verify-patches script if your project has one,
# or spot-check a known-patched file in the vendored tree)
ddev composer install # says "Nothing to install" despite the missing patchesFix — force a clean reinstall of the affected package (re-applies its patches):
ddev composer reinstall drupal/<pkg>Rule: after ANY interrupted composer run, treat the whole package tree as suspect. Reinstall the packages that were mid-flight, re-verify patches, and only THEN debug remaining errors — the error you saw during the broken window may already be gone. Check error-log timestamps: confirm a fatal reproduces NOW before engineering a fix for it.
Timeout-Killed ddev drush Commands Orphan In-Container Processes
Killing the host-side ddev drush ... process (Ctrl-C, tool timeout) does NOT kill the php process inside the web container. Orphans accumulate, contend for CPU, and make every subsequent drush bootstrap crawl (10+ minutes for drush cr/updb/updatedb:status — looks like a hang, is actually starvation).
Diagnose / clean up:
ddev exec "ps aux | grep -v grep | grep -E 'vendor/bin/drush|php /var/www'"
ddev exec "pkill -f 'vendor/bin/drush'"Two corollaries:
- Run long drush operations (
updbon a big upgrade, coldcr) ONCE, in the background, with a generous timeout — do not fire repeated shorter attempts; each kill adds another orphan. - A "hung then killed"
updbmay have already completed its real work — update hooks are recorded per-hook. Before re-running or panicking, check what actually executed:
ddev mysql -e "SELECT value FROM key_value WHERE collection='system.schema' AND name='<module>'"
ddev mysql -N -e "SELECT value FROM key_value WHERE collection='post_update' AND name='existing_updates'" | grep -o "<module>_post_update_[a-z0-9_]*"Docker Engine Wedge (Check Before Iterating on DDEV)
phpunit exits 137, background jobs die mid-run, ddev exec re-triggers full
image rebuilds, or every ddev start hits "container name already in use" —
looks like a DDEV problem but is often the Docker Desktop engine crashed
underneath still-resident app processes. Check this FIRST:
timeout 5 docker version # hangs on the Server section -> engine is dead
docker ps # if this responds while `docker version` hangs, engine is wedgedFix: killall -9 com.docker.backend && open -a Docker, poll docker ps
until it responds, then ddev start. Don't keep iterating on ddev-level
fixes (poweroff/mutagen reset/etc.) while the engine itself is down — none
of them can succeed. After the restart, watch for orphan containers and a
slow first drush: post-crash traps.
Host CPU Saturation (Containers Healthy, Requests Hang)
Host load well above core count; containers healthy and php -v instant, but
every request and drush bootstrap hangs (php-fpm workers blocked in
request_wait_answer on a stalled virtiofs bridge). No DDEV recovery fixes it
until load drops — shed load, then one ddev poweroff && ddev start. Details:
load-and-recovery.md.
Post-Recovery 404s With Route-Discovery Warnings
A 404 with route-discovery warnings right after a recovery (Docker restart,
mutagen reset, core update) that ddev drush cr does not fix is usually an
APCu-stale compiled container: php-fpm's opcode cache still holds pre-change
code even though cache_container in the DB is fresh. Fix: docker
restart ddev-<project>-web (forces fresh APCu) — not another cache clear.
Router TLS Reset While Containers Report Healthy
curl to https://<project>.ddev.site fails instantly with exit 35 ("Connection reset by peer" during TLS handshake) even though ddev describe shows everything OK and docker ps says ddev-router is healthy. The app is fine — the router is wedged.
Discriminate app vs router (bypasses the router entirely):
ddev exec "curl -s -o /dev/null -w '%{http_code}' http://localhost/<path>"Fix:
docker restart ddev-routerDocker Desktop overlay2 I/O Errors
If Docker Desktop gets into a bad state producing overlay2 or containerd I/O errors such as:
Error response from daemon: error creating temporary lease: write /var/lib/desktop-containerd/daemon/io.containerd.metadata.v1.bolt/meta.db: input/output errorError response from daemon: open /var/lib/docker/overlay2/...: input/output errorA normal quit and restart of Docker Desktop is not sufficient. You must force quit ALL Docker processes (via Activity Monitor or killall -9 Docker / killall -9 com.docker.hyperkit), then relaunch Docker Desktop. Only a full force quit clears the corrupted state.
"readdirent bad message" variant: signals VM-disk corruption at the
container-metadata level, not a transient overlay2 hiccup — repeated ddev
start will not fix it. Quarantine the corrupted container's metadata
directory instead of looping restarts (enter an alpine container via
nsenter and mv the offending /var/lib/docker/containers/<id> dir aside).
Unhealthy Containers / Mutagen Sync Hanging
After Docker crashes or force-quits, DDEV can get into a bad state where:
ddev starthangs at "Starting Mutagen sync process..."- Web container reports unhealthy (
phpstatus:FAILED,mailpit:FAILED) ddev mutagen resetfails with "CreateOrResumeMutagenSync Failure"
Fix (run in order):
# 1. Full power off to clean up all containers and networks
ddev poweroff
# 2. Start fresh
ddev startIf ddev poweroff doesn't resolve it:
# 1. Stop DDEV
ddev stop
# 2. Reset the Mutagen daemon
~/.ddev/bin/mutagen daemon stop
~/.ddev/bin/mutagen daemon start
# 3. Reset Mutagen sync (removes Docker volume, forces full resync)
ddev mutagen reset
# 4. Start fresh
ddev startMonitoring commands while troubleshooting:
ddev mutagen status -l # Detailed sync status
ddev mutagen monitor # Real-time sync progress
docker inspect --format "{{ json .State.Health }}" ddev-<project>-web # Container healthDisk Usage: Don't Trust ls or du
ls -la reports the logical size of sparse files (e.g. Docker.raw), which
can be far larger than what's actually consumed on disk; du over-reports on
APFS because it double-counts copy-on-write clones shared between snapshots.
Neither answers "how much space would this operation actually cost/free."
Trust only df deltas taken immediately before and after the operation.
Related Skills
- @drupal-config-mgmt - Config management workflows
- @drupal-contrib-mgmt - Module management with Composer
- @drupal-at-your-fingertips - General Drupal patterns
Official Documentation: https://ddev.readthedocs.io Drupal DDEV Quickstart: https://ddev.readthedocs.io/en/stable/users/quickstart/ Community Support: https://discord.gg/5wjP76mBJD
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

