The Manifest File
A Dockform manifest is a single YAML file that defines all resources needed for your Docker deployments. With it, you can declare contexts, stacks, environment variables, secrets, volumes, networks, and filesets in one place, making your infrastructure fully reproducible and declarative.
Overview
Dockform v0.8 introduces automatic discovery and multi-context support. Your manifest can be as simple as:
With this minimal configuration, Dockform automatically discovers stacks from your directory structure.
Full Schema Example
identifier: my-project # (1)!
sops:
age:
key_file: ${AGE_KEY_FILE}
recipients:
- age1ql3z7hjy54pw3hyww5ayyfg7zqgvc7w3j2elw8zmrj2kg5sfn9aqmcac8p
discovery: # (2)!
compose_files: [compose.yaml, docker-compose.yaml]
secrets_file: secrets.env
environment_file: environment.env
volumes_dir: volumes
contexts: # (3)!
default:
volumes:
app-data: {}
networks:
app-network:
driver: bridge
options:
com.docker.network.bridge.enable_icc: "false"
production:
volumes:
prod-data: {}
networks:
traefik: {}
stacks: # (4)!
default/web:
profiles: [production]
environment:
inline:
- DEBUG=false
project:
name: web-staging
deployments: # (5)!
staging:
description: Deploy all staging stacks
contexts: [default]
prod:
description: Deploy production only
stacks: [production/web, production/api]
- identifier is required and used to label all managed resources
- discovery (optional) customizes how Dockform finds stacks and filesets
- contexts maps Docker context names to their resource configurations
- stacks (optional) augments discovered stacks with profiles, environment, secrets, or project name
- deployments (optional) defines named groups for targeting specific contexts or stacks
identifier:
| Type | Default | Required |
|---|---|---|
| String | null |
The identifier labels all resources managed by Dockform. It's used for:
- Docker labels:
io.dockform.identifier=<identifier> - Resource discovery and cleanup
- Compose project scoping
Important
Changing the identifier of an existing deployment will not update already deployed resources. Use dockform destroy first if you need to change identifiers.
contexts:
| Type | Default | Required |
|---|---|---|
| Map | null |
The contexts map defines which Docker contexts (daemons) Dockform manages. Each key is a logical name for the context.
When a context does not specify host, the key must match an existing Docker Context on the host machine. When host is specified, Dockform connects directly to the given endpoint without requiring a pre-configured Docker context.
contexts:
default: {} # Local Docker daemon
remote-server: # Remote daemon — no Docker context setup needed
host: ssh://deploy@10.0.0.1
production:
host: ssh://deploy@prod.example.com
volumes:
app-data: {}
networks:
traefik: {}
host:
| Type | Default | Required |
|---|---|---|
| String | null |
Optional Docker host URI (e.g., ssh://user@host, tcp://host:2376, unix:///var/run/docker.sock). When set, Dockform uses DOCKER_HOST instead of DOCKER_CONTEXT for all Docker CLI invocations against this context.
This makes your manifest portable — you can clone the project on a new machine and deploy without manually creating Docker contexts first.
Tip
When host is omitted, the context key must match a Docker context configured on the host machine. You can create one with:
Context Resources
Each context can also define:
volumes:- Docker volumes to createnetworks:- Docker networks to create
contexts:
default:
volumes:
db-data: {}
app-config: {}
networks:
frontend:
driver: bridge
backend:
internal: true
discovery:
| Type | Default | Required |
|---|---|---|
| Map | (sensible defaults) |
Discovery controls how Dockform automatically finds stacks and filesets from your directory structure. Discovery is always enabled; this block only customizes the patterns used.
discovery:
compose_files: # Default: [compose.yaml, compose.yml, docker-compose.yaml, docker-compose.yml]
- stack.yml
secrets_file: .secrets.env # Default: secrets.env
environment_file: .env # Default: environment.env
volumes_dir: data # Default: volumes
How Discovery Works
Dockform scans directories matching your contexts:
my-project/
├── dockform.yml
├── default/ # ← Context "default"
│ ├── web/ # ← Stack "default/web"
│ │ ├── compose.yaml # ← Compose file (discovered)
│ │ ├── environment.env # ← Env file (discovered)
│ │ ├── secrets.env # ← Secrets (discovered)
│ │ └── volumes/ # ← Filesets directory
│ │ └── config/ # ← Fileset "config"
│ └── api/
│ └── compose.yaml
└── production/ # ← Context "production"
└── traefik/
└── compose.yaml
stacks:
| Type | Default | Required |
|---|---|---|
| Map | null |
The stacks block augments discovered stacks. It does not create new stacks—it adds configuration to stacks found through discovery.
Stack keys use the format context/stack:
stacks:
default/web:
profiles: [production, metrics]
environment:
inline:
- LOG_LEVEL=debug
project:
name: web-prod
production/api:
secrets:
sops:
- api-secrets.env
Augmentation Fields
| Field | Purpose |
|---|---|
profiles |
Compose profiles to activate |
environment.inline |
Additional environment variables |
environment.files |
Additional env files |
secrets.sops |
Additional SOPS-encrypted files |
project.name |
Override Compose project name |
Note
Discovery sets root, files, and base env-file. The stacks block adds to these, it doesn't replace them.
sops:
| Type | Default | Required |
|---|---|---|
| Map | null |
Configures SOPS for secret decryption. Supports Age and PGP backends.
sops:
age:
key_file: ${AGE_KEY_FILE}
recipients:
- age1ql3z7hjy54pw3hyww5ayyfg7zqgvc7w3j2elw8zmrj2kg5sfn9aqmcac8p
pgp:
keyring_dir: ~/.gnupg
recipients:
- 0xDEADBEEFCAFEBABE
See Secrets Workflow for detailed setup.
deployments:
| Type | Default | Required |
|---|---|---|
| Map | null |
Deployments define named groups for targeting specific contexts or stacks with CLI commands.
deployments:
staging:
description: Deploy all staging stacks
contexts: [default]
production:
description: Deploy production services
stacks:
- production/web
- production/api
- production/traefik
Use with --deployment flag:
Project Structure
A typical Dockform v0.8 project:
my-project/
├── dockform.yml # Manifest file
├── default/ # Context: default (local Docker)
│ ├── web/ # Stack: default/web
│ │ ├── compose.yaml
│ │ ├── environment.env
│ │ └── volumes/
│ │ └── static/ # Fileset: synced to volume
│ ├── api/
│ │ └── compose.yaml
│ └── traefik/
│ ├── compose.yaml
│ └── volumes/
│ └── config/
└── production/ # Context: production (remote)
└── web/
└── compose.yaml
Minimal vs Full Example
identifier: myapp
sops:
age:
key_file: ${AGE_KEY_FILE}
contexts:
default:
volumes:
app-data: {}
networks:
traefik: {}
production:
volumes:
prod-data: {}
stacks:
default/web:
profiles: [debug]
environment:
inline:
- DEBUG=true
production/web:
profiles: [production]
deployments:
dev:
contexts: [default]
prod:
contexts: [production]