Appearance
Choosing a backend
The same .dq/config.yml runs on four. They are not equivalent, and the differences are the reason dqx has a switch command rather than an opinion.
One backend at a time
Ports 80 and 443 have a single owner per machine, and each backend wants them: docker's shared router, DDEV's proxy, Lerd's nginx, Herd's. Two backends cannot serve at once.
So a project pinned to DDEV and a project on docker are not two things you run side by side — they are two things you switch between:
bash
dqx kill # frees 80 and 443, whichever backend was holding them
cd ../other-project && dqx updqx kill --dry-run says what it would stop first, and dqx kill --all also stops the runtimes themselves when you want their memory back. Within one backend the opposite is true: docker's shared router serves every project at the same time, which is the whole reason it exists.
| Docker Compose | DDEV | Lerd | Herd | |
|---|---|---|---|---|
| Platform | macOS, Linux, Windows | macOS, Linux, Windows | Linux, macOS | macOS, Windows |
| Several sites per project | yes | one registration per directory | yes | yes |
| Isolation | full | full | full | shares the host's PHP |
| File access | bind mount | its own sync, keeping hot files off the mount | bind mount | native |
| Cost | free | free | free | Pro is paid for databases and mail |
| Page render, authenticated | 104 ms | 66 ms | 193 ms | not measured |
| Starting all four | 16.8 s | 141.7 s | 301.9 s | not measured |
| Stopping all four | 9.6 s | 28.6 s | 28.6 s | not measured |
| Memory for all four | 4.4 GB | 9.6 GB | 1.9 GB | host processes only |
| Containers for all four | 19 | 22 | 10 | none |
| What dqx generates | the whole stack | its config, plus per-site directories | its config | almost nothing |
What "all four" means. One measured run with four projects open at the same time — the way the machine is actually used — totalling 19 to 22 containers depending on the backend, and 23 authenticated, database-and-search-backed pages. Not a synthetic benchmark and not a vendor's page.
Per project that is roughly 1.1 GB on docker against 2.4 GB on DDEV, and about 4 seconds to start against 35. The largest of the four — seven sites, Elasticsearch and a queue worker — starts in 2.9 s on docker against 63.1 s on DDEV, which is where the difference stops being a number and becomes a morning.
Herd was not measured in this run: it needs a paid seat before a database can be evaluated at all, so its column is honest rather than flattering.
The short version
Docker Compose is the default. It runs everywhere, isolates completely, and dqx generates the whole stack from the declaration — which means the environment is disposable and identical for everyone. If file access is what hurts, OrbStack is worth trying before changing backend: the same engine, 4–5× faster on a large tree, and nothing in the project changes. It earns no column of its own here, because on this table's own axes it measures the same as Docker Desktop — starts and warm pages are identical. What it changes is everything cold, where it is worth about 1.8×.
DDEV is the one to reach for when a page render is what hurts. Its sync keeps the hot files off the mount — 66 ms against docker's 104 on a real authenticated page. It costs the rest of the day: starts are 8.4× slower and stops 3× slower, and a project serving several sites is several DDEV registrations to bring up one after another. On the fleet's larger multi-site projects that is felt every morning.
Lerd suits Linux, and it is by far the lightest — 1.9 GB for the same four projects, in ten containers rather than twenty. It pays for that twice: ~1.65× slower per page than DDEV, and the slowest of the three to start the set (301.9 s). It is also the least widely used, which is felt when something is strange.
Herd is the fastest and the least isolated. PHP runs on the host, which is why it is quick and also why two projects needing different extensions is a problem rather than a setting. The database and mail features are behind Herd Pro.
Changing your mind
bash
dqx switch ddevThe project's repository does not notice: what changes is what dqx generates and where it runs commands. What the project declares stays the declaration.
Read the per-backend pages for what each one cannot do, which is usually the part that decides it.