marea.yaml is the declarative configuration file Marea reads on every
invocation. It describes:
- which optional plugins to load
- where to find local configuration and where to write build artefacts
- a list of deploys (one per environment / cluster)
- a list of releases per deploy (one per Elixir release)
- any other configuration needed by any plugin (e.g. AWS)
Plugins extend the schema at runtime. Core Marea (the schema you get
with no plugins listed) only knows about plugins:, marea_dir:,
state_dir:, cmd_prefix:, and the bare deploys.<d>.releases.<r>
shape — every other field on this page is contributed by a plugin
(Helm adds helm: and the :helm deploy type, Docker adds
docker: and the :elixir / :dockerfile_dir release types,
Python adds release-level python:, Aws adds aws:, and so on).
For your own plugins, see
06-plugin-development.md.
To inspect the live, plugin-enriched schema for the project you're in,
run marea schema show (or marea schema show --json for the JSON
Schema form). See plugins/base.md.
Where Marea looks for the file
On startup, Marea picks the first existing path from:
marea.yamlconfig/marea.yamlmarea.d/marea.yaml
If none exist, any non-setup command stops and suggests running
marea setup init-marea, which scaffolds a minimal marea.d/marea.yaml and
the marea.d/ directory layout for you (see
02-installation.md).
Top-level fields
plugins: # list of plugin module names to load (in addition to base plugins)
marea_dir: # directory holding configs/secrets/deploys/charts (default: marea.d)
state_dir: # directory holding runtime state (default: .marea)
cmd_prefix: # optional shell prefix per command type (e.g. running inside docker)
deploys: # map of deploy-name → deploy spec
# contributed by Marea.Plugins.Aws:
aws: # map of aws-id → aws spec| Field | Type | Default | Notes |
|---|---|---|---|
plugins | list of strings | [] | Module names like Marea.Plugins.Helm. Loaded on top of the base plugins (Setup, Build, Run, Base). Container/Helm/Python/AWS support is opt-in: list Marea.Plugins.Docker, Marea.Plugins.Helm, Marea.Plugins.Docker.Python (the docker/python plugin), Marea.Plugins.Aws, etc. (plugin_deps: resolves transitive dependencies — listing Helm is enough to also load Docker and Build). |
marea_dir | string | marea.d | Where Marea looks for configs/, secrets/, deploys/, templates/, helms/, and writes generated charts. |
state_dir | string | .marea | Working directory for build artefacts, last-values memory, and the deferred next_cmd script. |
cmd_prefix | map (atom → string) | nil | Per-command shell prefix. Currently only build: is recognised — useful when builds must run in a Linux container on a non-Linux host. |
deploys | map | {} | Each entry is a deploy_spec (see below). |
aws | map | nil | Contributed by the AWS plugin; see AWS configuration. |
cmd_prefix example:
cmd_prefix:
build: docker run --rm -v $PWD:/work -w /work my-builder-imageWhen set, build-related shell calls are wrapped:
docker run … sh -c '<original cmd>'.
Deploy spec
A deploy corresponds to a destination (e.g. a Kubernetes namespace on a particular cluster). It carries cluster-level config plus a map of releases that should run there.
deploys:
staging:
type: helm # contributed by Marea.Plugins.Helm
cookie: secret!cookies!staging
helm: # contributed by Marea.Plugins.Helm
chart: my-app # helm release name (default: deploy name, dasherised)
namespace: my-app-staging
kube_context: staging-cluster
secret_values_files:
- prod-values.yaml
chart_dir: helms/my-app # optional, see below
docker: # contributed by Marea.Plugins.Docker (deploy-level defaults)
platform: linux/amd64
elixir_vsn: "1.17.3"
releases:
api:
type: elixir
helm:
template: deployment.yaml
domains:
- api.staging.example.com| Field | Contributed by | Default | Notes |
|---|---|---|---|
type | base + plugins | first contributed deploy type | Enum populated through the marea_deploy_types/1 chain. With only Marea.Plugins.Helm loaded, the only value is :helm and it defaults in. |
cookie | base | — | Erlang cookie. Can use a secret!file!key reference. |
helm.chart | Helm | deploy name | Helm release name. Underscores become dashes. |
helm.namespace | Helm | required | Kubernetes namespace. Helm commands fail without it. |
helm.kube_context | Helm | — | If set, all helm invocations include --kube-context. |
helm.secret_values_files | Helm | [] | Files under <marea_dir>/secrets/ passed to helm via -f. |
helm.chart_dir | Helm | — | Use a pre-existing Helm chart on disk instead of generating one from releases:. Mutually exclusive with releases:. |
docker | Docker | — | Default Docker config for all releases (see plugins/docker.md). |
releases | base | — | Required when helm.chart_dir is not set. |
Marea.Plugins.Helm enforces that a deploy of type: helm has either
releases: (Marea generates the chart) or helm.chart_dir: (you
maintain the chart yourself), but not both.
Release spec
Each release becomes one Kubernetes workload. With
Marea.Plugins.Docker loaded (which Helm pulls in transitively),
two release build types are available:
elixir: Marea writes a Dockerfile from a template and builds a Docker image of an Elixir release.dockerfile_dir: you maintain a Dockerfile yourself in a subdirectory undermarea_dir; Marea just runsdocker build.
The type: enum is populated through the
marea_release_types/1 plugin chain, so a project that loads a
different image-build plugin would see different values here.
releases:
api:
type: elixir
helm: # contributed by Marea.Plugins.Helm
template: deployment.yaml
values:
replicas: 3
env:
PORT: "4000"
docker: # contributed by Marea.Plugins.Docker
elixir_vsn: "1.17.3"
rebuild_deps:
- crc32cer
path_deps:
- ../shared_lib
platform: linux/arm64
python: # contributed by docker.python (Marea.Plugins.Docker.Python)
version: "3.12"
requirements:
- "boto3==1.34.0"
domains:
- api.staging.example.com| Field | Contributed by | Notes |
|---|---|---|
type | base + plugins | Enum populated through the marea_release_types/1 chain. With Marea.Plugins.Docker loaded the values are :elixir (default) and :dockerfile_dir. |
helm.template | Helm | Template filename, resolved against <marea_dir>/templates/ first, then Marea's built-in templates. |
helm.values | Helm | Free-form values passed to the template as @values. |
docker | Docker | Per-release Docker overrides (deep-merged with the deploy-level docker:). See plugins/docker.md for the full key list. |
docker.python | docker.python | Adds a uv-managed Python venv to the build image, nested inside docker:. See plugins/docker-python.md. |
domains | base | List of domain names. Used by marea aws route53 update-deploy-domains. |
AWS configuration
Loaded only when Marea.Plugins.Aws is in your plugins: list.
aws:
default:
profile: my-aws-profile
region: eu-west-1
account_id: "123456789012"
ecr:
image_header: my-org/
route53:
example.com.:
cnames:
alb-staging: lb.example.com.
alb-prod: lb-prod.example.com.| Field | Notes |
|---|---|
<aws-id> (e.g. default) | Selectable with --aws-id / -a. The single-entry case auto-selects. |
profile | AWS CLI profile name (matches ~/.aws/credentials). Defaults to the <aws-id>. |
region | AWS region. Required for any AWS command. |
account_id | Used to construct the ECR registry URL for aws ecr login-docker. |
ecr.image_header | Prefix prepended to ECR repository names (e.g. my-org/). |
route53.<zone>.cnames.<name> | Named CNAME targets selectable with --cname for route53 create / update-deploy-domains. |
The s3: plugin block is also accepted under each <aws-id> entry
when needed:
aws:
default:
s3:
id: secret!aws_creds!access_key_id
secret: secret!aws_creds!secret_access_keyThese credentials are used only by aws s3 sync-in / sync-out.
The marea.d/ directory layout
<marea_dir>/
├── marea.yaml
├── configs/ # arbitrary config files referenced by helm templates
│ └── app.env
├── secrets/ # secrets and helm "values" files
│ ├── cookies.yaml
│ └── prod-values.yaml
├── deploys/<deploy>/ # generated values.yaml per deploy
├── charts/<deploy>/ # generated helm chart per deploy
├── helms/<chart>/ # optional: hand-maintained helm charts
└── templates/ # optional overrides for built-in templates
├── deployment.yaml
└── dockerfile_v01configs/— arbitrary files (often.env-style or YAML) that helm templates can read via the@config_filesassign.secrets/— same idea, but base64-encoded into Kubernetes Secrets, and accessible viasecret!<filename>!<key>references inmarea.yaml.deploys/<deploy>/values.yaml— written bybuild helmto record the most recent image tag per release.charts/<deploy>/— output ofmarea helm chart. Always regenerated fromreleases:(or copied fromhelm.chart_dir).templates/<name>— overrides Marea's built-in templates with the same name (Helm templates ending in.yaml, Dockerfile templates with no extension).
YAML includes
Anywhere a string value is expected, you can use the include! prefix
to inline another YAML file:
deploys:
staging:
helm: include!fragments/staging-helm.yaml
releases:
api: include!releases/api.yamlPaths are relative to the file containing the directive. Nested includes are supported. Circular includes raise an error:
Circular include detected: /…/releases/api.yamlSecret references
In any string value (e.g. cookie: or aws.s3.id), the form
secret!<file>!<key> is resolved against the corresponding YAML file
under <marea_dir>/secrets/:
deploys:
staging:
cookie: secret!cookies!staging# marea.d/secrets/cookies.yaml
staging: a-secret-cookie
prod: another-cookieIf the secret is missing, Marea aborts with Cannot find secret ….
Last-values memory
<state_dir>/last_values (default .marea/last_values) is an Erlang
term file. After every successful command Marea persists :deploy,
:release, :aws_id, :route53_zone, and the most recent build
metadata (:image, :git_vsn, …). On the next run, those become
defaults for --deploy, --release, and friends.
You don't normally edit this file. To clear it, delete it.
Validation errors
The schema is enforced with Zoi.
Validation errors point at the marea.yaml path and render every
constraint violation; for example:
Error in marea.d/marea.yaml:
deploys.staging.helm.namespace: required
deploys.staging.releases.api.docker: docker.dockerfile_dir is required for type: dockerfile_dirIf a field looks like it should be allowed but isn't, check whether the
plugin that contributes it is in your plugins: list.