Skip to content

Core Concepts

dde manages two layers of Docker containers:

System services are long-running, shared infrastructure containers managed by system:install. They run independently of any project and are shared across all projects on the machine:

  • Traefik — Reverse proxy on ports 80 and 443. Routes traffic to project containers based on labels.
  • dnsmasq — DNS server that resolves *.test domains to 127.0.0.1. Forwards other queries to upstream DNS (default: 9.9.9.9, 149.112.112.112).
  • SSH agent — Holds SSH keys and makes them available to project containers via a shared volume.

Project containers are defined in your project’s docker-compose.yml and started/stopped by project:up and project:down. These include your application container(s) and any per-project services (databases, caches, mail).

The supported per-project services are:

ServiceDefault versionDefault port
MariaDB11.83306
PostgreSQL18.35432
Valkey96379
Mailpitlatest8025

dde resolves configuration values using a layered override chain. Values from higher layers take precedence:

CLI options (highest priority)
|
Project config (.dde/config.yml)
|
Global config (~/.dde/config.yml)
|
Built-in defaults (lowest priority)

For example, the MariaDB version resolves as follows:

  1. If .dde/config.yml specifies an explicit version for the mariadb service, that version is used.
  2. Otherwise, if ~/.dde/config.yml defines a global service version override, that version is used.
  3. Otherwise, the built-in default (11.8) is used.

Located at ~/.dde/config.yml. Controls machine-wide defaults:

output: text # Default output format (text or json)
dns:
forward:
- 9.9.9.9
- 149.112.112.112
ssh:
keys: [] # SSH key paths to add to the agent
services:
mariadb:
version: "11.8"
postgres:
version: "18.3"

Located at .dde/config.yml inside the project root. Controls per-project settings:

name: my-app
services:
- name: mariadb
version: "11.8"
- name: valkey
containers:
web:
shell: /bin/bash

project:init creates a .dde/ directory in your project root with the following structure:

.dde/
.gitignore # Excludes data/ and snapshots/ from version control
config.yml # Project configuration
data/ # Persistent data for services (database files, etc.)
snapshots/ # Database snapshots
hooks/ # Lifecycle hook scripts
project.up.pre/ # Runs before project:up
project.up.post/ # Runs after project:up
project.down.pre/ # Runs before project:down
project.down.post/ # Runs after project:down
adapters/ # Custom adapter scripts
plugins/ # Project-local plugin definitions

The .gitignore file excludes data/ and snapshots/ so that database files and snapshots are not committed to version control. Everything else — including config.yml, hooks, adapters, and plugins — is intended to be committed and shared with the team.

All project containers and system services are connected to a shared Docker network called dde. This network enables:

  • Traefik to discover and route traffic to project containers
  • Project containers to reach system services (e.g., the SSH agent)
  • Cross-project communication when needed

The network is created automatically by system:install and attached to project containers via the docker-compose override that project:up generates.

Every dde command supports the --output option to control the output format:

  • text (default) — Human-readable terminal output
  • json — Machine-readable JSON, suitable for scripting and CI pipelines
Terminal window
dde project:describe --output=json

The default output format can be set globally in ~/.dde/config.yml via the output key.