The file accepts version, defaults, moved, and ten resource sections. All section keys are camelCase. Every section is optional — include only what you need (but the file must contain at least one resource section):
version: "1"defaults: # default values applied to all monitors monitors: frequencySeconds: 60 enabled: true regions: [us-east, eu-west]tags: [] # organization-wide labelsenvironments: [] # deployment stages with variablessecrets: [] # vault secrets (write-only)alertChannels: [] # where notifications are sentnotificationPolicies: [] # escalation chains and match ruleswebhooks: [] # platform event webhooksresourceGroups: [] # composite health groupsmonitors: [] # the monitoring checks themselvesdependencies: [] # third-party service subscriptionsstatusPages: [] # public status pages
The schema is strict: unknown top-level keys (and unknown keys inside any resource) are rejected at validate time.
version: "1"monitors: - name: API Health type: HTTP config: url: https://api.example.com/health method: GET
The schema version. Currently "1" is the only supported value. The CLI warns on unrecognized versions but does not reject them. A config consisting of only version (no resource sections) is rejected with “Config has no resource definitions”.
Defaults are applied with shallow per-field merge: if a monitor sets a field, the monitor value wins. Nested objects like incidentPolicy are replaced entirely, not deep-merged. A default incidentPolicy must be complete — triggerRules, confirmation, and recovery are all required whenever the block is present.
monitors: - name: API Health type: HTTP config: url: ${API_URL:-https://api.example.com/health} method: GET
Environment variables are resolved after YAML parsing, inside string values only — values containing YAML metacharacters can never alter document structure. If a required variable is missing (or set to the empty string), the CLI exits with an error listing all unresolved variables. Use $$ for a literal $, and ${VAR:-} to explicitly allow an empty value.
Because interpolation happens inside string values, ${VAR} only works in string fields (URLs, tokens, names). Numeric fields like frequencySeconds cannot be interpolated — frequencySeconds: ${FREQ:-60} fails validation with “Expected number, received string”. Vary numeric fields across environments with separate files instead.
Environment variable interpolation (${VAR}) is different from vault secrets. Variables are resolved from the shell environment at deploy time. Vault secrets are stored in DevHelm and referenced by key in auth blocks.
Or point to a directory (all *.yml and *.yaml files are loaded in sorted order):
devhelm deploy -f config/ --yes
Sections from all files are concatenated. Duplicate names within a resource type are a validation error (“names must be unique within each resource type”) — files must define disjoint resources; there is no override/last-wins merging. The defaults block is the one exception: later files’ defaults.monitors fields shallow-merge over earlier ones.