Kamal Configuration
You are an expert in deploying applications with Kamal. Your goal is to help structure a clear, correct config/deploy.yml — the single file that drives every Kamal deployment.
Kamal reads its configuration from config/deploy.yml. This skill walks through the required keys, the full set of top-level options and their defaults, per-environment destinations (-d), extensions (x-), and how to keep the file DRY with YAML anchors.
Before You Start
Inspect what already exists before asking the user questions:
- Read
config/deploy.ymlif it exists — it tells you the service name, servers, registry, and which options are already tuned. - Look for
config/deploy.<destination>.ymlfiles (e.g.config/deploy.staging.yml) — these signal the project already uses destinations. - Check
.kamal/secretsfor referenced secret names so you don't duplicate or contradict them.
If there is no config/deploy.yml, generate one with kamal init, which creates the configuration file plus a .kamal/secrets file and sample hooks in .kamal/hooks.
How the Config File Works
| Action | Command |
|---|---|
Create config/deploy.yml, .kamal/secrets, and sample hooks |
kamal init |
| Display the resolved config (with destinations merged in) | kamal config |
After any edit, run kamal config to print the resolved configuration and confirm Kamal parses it the way you expect.
Note: Kamal rejects unrecognized keys. A typo'd or invented key is an error, not a silent no-op — see Extensions for the one supported escape hatch.
Step-by-Step Walk-Through
Step 1: Set the required key
service is the only required value. It is used as the container name prefix, so keep it short and stable.
service: myapp
Step 2: Point at an image
image is the Docker image name. The image will be pushed to the configured registry.
image: my-image
Step 3: Add the deploy targets
These three blocks describe where and how the app runs. Each is a topic of its own — set the keys here and follow the cross-references for detail:
registry:
... # Docker registry — see servers / official Registry docs
servers:
- 192.168.0.1 # a bare list is implicitly the `web` role
env:
clear:
DATABASE_HOST: mysql-db1
secret:
- DATABASE_PASSWORD
- For server lists, roles, and tags, see the servers skill.
- For
clear/secretenv, tags, and.kamal/secrets, see the env skill.
Step 4: Tune the top-level options
Set only the options you need to change from their defaults. The most commonly adjusted ones:
| Key | Purpose | Default |
|---|---|---|
primary_role |
Which role is primary when you have no web role |
web |
retain_containers |
How many old containers and images to keep | 5 |
readiness_delay |
Seconds to wait after a container is running (only for containers with no proxy and no healthcheck) | 7 |
deploy_timeout |
Seconds to wait for a container to become ready | 30 |
drain_timeout |
Seconds to wait for a container to drain | 30 |
require_destination |
Require a -d destination on every command |
false |
minimum_version |
Minimum Kamal version required to deploy this config | nil |
primary_role: workers
retain_containers: 3
require_destination: true
For the complete list of every top-level key and default, see references/config-keys.md.
Step 5: Validate
Run kamal config to render the merged result and catch parse errors or unexpected defaults before deploying.
Destinations (-d)
Destinations let one project target multiple environments from one base config plus a per-destination overlay.
When you pass a destination with the -d flag, e.g. kamal deploy -d staging, Kamal also reads config/deploy.staging.yml and merges it with the base config/deploy.yml.
# config/deploy.yml (base)
service: myapp
servers:
- 192.168.0.1
# config/deploy.staging.yml (overlay, merged over the base)
servers:
- 10.0.0.5
Secrets follow the destination too. With destinations, Kamal looks for <secrets_path>-common first and then <secrets_path>.<destination> (e.g. .kamal/secrets-common, then .kamal/secrets.staging), with later files overriding earlier ones.
To make a destination mandatory so nobody deploys to the wrong place by accident, set require_destination: true.
Extensions (x-)
Kamal will not accept unrecognized keys in the configuration file. To declare a reusable block without triggering an error, prefix the section with x-. Kamal ignores any x--prefixed key and treats it as an extension.
This is what makes YAML anchors usable in deploy.yml: define the anchor under an x- key so Kamal skips it, then alias it where it counts.
DRY Config with YAML Anchors
You can re-use parts of your configuration by defining them as anchors and referencing them with aliases. Anchors begin with x- and are defined at the root level of deploy.yml.
Define the anchor once:
x-worker-healthcheck: &worker-healthcheck
health-cmd: bin/worker-healthcheck
health-start-period: 5s
health-retries: 5
health-interval: 5s
Then reference it via the alias, merging it in with <<:
servers:
worker:
hosts:
- 867.53.0.9
cmd: bin/jobs
options:
<<: *worker-healthcheck
This keeps a single source of truth for shared blocks (like a healthcheck reused across multiple worker roles) without repeating yourself.
Reusable Command Shortcuts
The top-level aliases key defines shortcuts for Kamal commands — for example a console alias or a staging_deploy: deploy -d staging. These are configured in the same file. For the full pattern, see the aliases skill.
Related Skills
- setup: For a first-time Kamal setup and your first deployment.
- servers: For the
serversblock — host lists, roles, tags, and per-role options. - env: For the
envblock —clear/secretvalues, tags, and.kamal/secrets. - aliases: For defining command shortcuts under the
aliaseskey.