Mutagen in DDEV: Functionality, Issues, and Debugging
Mutagen has been a part of DDEV for years, providing dramatic performance improvements for macOS and traditional Windows users. It’s enabled by default on these platforms, but understanding how it works, what can go wrong, and how to debug issues is key to getting the most out of DDEV.
Contributor Training Video
See the January 22, 2026 Contributor Training based on this blog:
See the slides for the training video.
What Mutagen Does
Mutagen is an asynchronous file synchronization tool that decouples in-container reads and writes from reads and writes on the host machine. Each filesystem enjoys near-native speed because neither is stuck waiting on the other.
Traditional Docker bind-mounts check every file access against the file on the host. On macOS and Windows, Docker’s implementation of these checks is not performant. Mutagen solves this by maintaining a cached copy of your project files in a Docker volume, syncing changes between host and container asynchronously.
Mostly for PHP
The primary target of Mutagen syncing is PHP files. These were the fundamental problem with Docker as the number of files in a Docker-hosted PHP website grew into the Composer generation with tens of thousands of files, so php-fpm had to open so very many of them all at once. Now with DDEV on macOS using Mutagen, php-fpm is opening files that are just on its local Linux filesystem, not opening ten thousand files that all have to be verified on the host.
Webserving Performance Improvement
Mutagen has made many cohorts of developers very, very happy with the webserving performance. One dev said “the first time I tried it I cried.”
Filesystem Notifications
Mutagen supports filesystem notifications (inotify/fsnotify), so file-watchers on both the host and inside the container are notified when changes occur. This is a significant advantage for development tools that would otherwise need to poll for changes.
How Mutagen Works in DDEV
When Mutagen is enabled, DDEV:
- Mounts a Docker volume onto
/var/wwwinside the web container - A Linux Mutagen daemon is installed inside the web container
- A host-side Mutagen daemon is started by DDEV
- The two daemons keep each other up-to-date with changes on either side
Lifecycle
ddev start: Starts the Mutagen daemon on the host if not running, creates or resumes sync sessionddev stop: Flushes sync session to ensure consistency, then pauses itddev composer: Triggers synchronous flush after completion to sync massive filesystem changesddev mutagen reset: Removes the Docker volume and the sync session will then be recreated from scratch (from the host-side contents) onddev start.
Upload Directories
DDEV automatically excludes user-generated files in upload_dirs from Mutagen syncing, using bind-mounts instead. For most CMS types, this is configured automatically, for example:
- Drupal:
sites/default/files - WordPress:
wp-content/uploads - TYPO3:
fileadmin,uploads
If your project has non-standard locations, override defaults by setting upload_dirs in .ddev/config.yaml.
We do note that upload_dirs is not an adequate description for this behavior. It was originally intended for user-generated files, but now is used for heavy directories like node_modules, etc.
Common Issues and Caveats
Initial Sync Time
The first-time Mutagen sync takes 5-60 seconds depending on project size. A Magento 2 site with sample data might take 48 seconds initially, 12 seconds on subsequent starts. If sync takes longer than a minute, you’re likely syncing large files or directories unnecessarily.
Large node_modules Directories
Frontend build tools create massive node_modules directories that slow Mutagen sync significantly. Solution: Add node_modules to upload_dirs:
upload_dirs: #upload_dirs entries are relative to docroot
- sites/default/files # Keep existing CMS defaults
- ../node_modules # Exclude from Mutagen
Then run ddev restart. The directory remains available in the container via Docker bind-mount.
File Changes When DDEV is Stopped
If you change files (checking out branches, running git pull, deleting files) while DDEV is stopped, Mutagen has no awareness of these changes. When you start again, it may restore old files from the volume.
Solution: Run ddev mutagen reset before restarting if you’ve made significant changes while stopped. That removes the volume so everything comes first from the host side in a fresh sync.
Simultaneous Changes
If the same file changes on both host and container while out of sync, conflicts can occur. This is quite rare but possible with:
- Scripts running simultaneously on host and in container
- Massive branch changes
- Large
npm installoryarn installoperations
Best practices:
- Do Git operations on the host, not in the container
- Use
ddev composerfor most composer operations - Run
ddev mutagen syncafter major Git branch changes - Run
ddev mutagen syncafter manual Composer operations done inside the container
Disk Space Considerations
Mutagen increases disk usage because project code exists both on your computer and inside a Docker volume. The upload_dirs directories are excluded to mitigate this.
Watch for volumes larger than 5GB (warning) or 10GB (critical). Use ddev utility mutagen-diagnose --all to check all projects.
Debugging Mutagen Issues
The New ddev utility mutagen-diagnose Command
DDEV now includes a diagnostic tool that automatically checks for common issues:
ddev utility mutagen-diagnose
This command analyzes:
- Volume sizes: Warns if >5GB, critical if >10GB
- Upload directories configuration: Checks if properly configured for your CMS
- Sync session status: Reports problems with the sync session
- Large directories: Identifies
node_modulesand other large directories being synced - Ignore patterns: Validates Mutagen exclusion configuration
Use --all flag to analyze all Mutagen volumes system-wide:
ddev utility mutagen-diagnose --all
The diagnostic provides actionable recommendations like:
⚠ 3 node_modules directories exist but are not excluded from sync (can cause slow sync)
→ Add to .ddev/config.yaml:
upload_dirs:
- sites/default/files
- web/themes/custom/mytheme/node_modules
- web/themes/contrib/bootstrap/node_modules
- app/node_modules
→ Then run: ddev restart
Debugging Long Startup Times
If ddev start takes longer than a minute and ddev utility mutagen-diagnose doesn’t give you clues about why, watch what Mutagen is syncing:
ddev mutagen reset # Start from scratch
ddev start
In another terminal:
while true; do ddev mutagen st -l | grep "^Current"; sleep 1; done
This shows which files Mutagen is working on:
Current file: vendor/bin/large-binary (306 MB/5.2 GB)
Current file: vendor/bin/large-binary (687 MB/5.2 GB)
Current file: vendor/bin/large-binary (1.1 GB/5.2 GB)
Add problem directories to upload_dirs or move them to .tarballs (automatically excluded).
Monitoring Sync Activity
Watch real-time sync activity:
ddev mutagen monitor
This shows when Mutagen responds to changes and helps identify sync delays.
Manual Sync Control
Force an explicit sync:
ddev mutagen sync
Check sync status:
ddev mutagen status
View detailed status:
ddev mutagen status -l
Troubleshooting Steps
-
Verify that your project works without Mutagen:
ddev config --performance-mode=none && ddev restart -
Run diagnostics:
ddev utility mutagen-diagnose -
Reset to clean
.ddev/mutagen/mutagen.yml:# Backup customizations first mv .ddev/mutagen/mutagen.yml .ddev/mutagen/mutagen.yml.bak ddev restart -
Reset Mutagen volume and recreate it:
ddev mutagen reset ddev restart -
Enable debug output:
DDEV_DEBUG=true ddev start -
View Mutagen logs:
ddev mutagen logs -
Restart Mutagen daemon:
ddev utility mutagen daemon stop ddev utility mutagen daemon start
Advanced Configuration
Excluding Directories from Sync
Recommended approach: Use upload_dirs in .ddev/config.yaml:
upload_dirs:
- sites/default/files # CMS uploads
- ../node_modules # Build dependencies
- ../vendor/bin # Large binaries
Advanced approach: Edit .ddev/mutagen/mutagen.yml after removing the #ddev-generated line:
ignore:
paths:
- "/web/themes/custom/mytheme/node_modules"
- "/vendor/large-package"
Then add corresponding bind-mounts in .ddev/docker-compose.bindmount.yaml:
services:
web:
volumes:
- "../web/themes/custom/mytheme/node_modules:/var/www/html/web/themes/custom/mytheme/node_modules"
Always run ddev mutagen reset after changing mutagen.yml.
Git Hooks for Automatic Sync
Add .git/hooks/post-checkout and make it executable:
#!/usr/bin/env bash
ddev mutagen sync || true
chmod +x .git/hooks/post-checkout
Use Global Configuration for performance_mode
The standard practice is to use global configuration for performance_mode so that each user does what’s normal for them, and the project configuration does not have configuration that might not work for another team member.
Most people don’t have to change this anyway; macOS and traditional Windows default to performance_mode: mutagen and Linux/WSL default to performance_mode: none.
When to Disable Mutagen
Disable Mutagen if:
- You’re on Linux or WSL2 (already has native performance)
- Filesystem consistency is more critical than webserving performance
- You’re troubleshooting other DDEV issues
Disable per-project:
ddev mutagen reset && ddev config --performance-mode=none && ddev restart
Disable globally:
ddev config global --performance-mode=none
Mutagen Data and DDEV
DDEV uses its own Mutagen installation, normally in ~/.ddev, but using $XDG_CONFIG_HOME when that is defined.
- Binary location:
$HOME/.ddev/bin/mutagenor${XDG_CONFIG_HOME}/ddev/bin/mutagen - Data directory:
$HOME/.ddev_mutagen_data_directory
Access Mutagen directly:
ddev utility mutagen sync list
ddev utility mutagen sync monitor <projectname>
Summary
Mutagen provides dramatic performance improvements for macOS and traditional Windows users, but understanding its asynchronous nature is key to avoiding issues:
- Use
ddev utility mutagen-diagnoseas your first debugging step - Configure
upload_dirsto exclude large directories likenode_modulesor heavy user-generated files directories - Run
ddev mutagen resetafter file changes when DDEV is stopped - Do Git operations on the host, not in the container
- Monitor sync activity with
ddev mutagen monitorwhen troubleshooting
The benefits far outweigh the caveats for most projects, especially with the new diagnostic tools that identify and help resolve common issues automatically.
For more information, see the DDEV Performance Documentation and the Mutagen documentation.
Copilot was used to create an initial draft for this blog, and for subsequent reviews.