Overlay merge strategy
Conduit merges a configuration overlay into the on-disk file layer using section replace for most top-level configuration keys; a few surfaces use deep merge with documented list and match-by-name rules. For how layers fit together, see Configuration model; for apply and reload steps, see Reload and export.
Section replace (default)
If the overlay includes a top-level key, that entire section from the file layer is replaced by the overlay's section (scalars and nested structure as present in the patch).
Examples: listeners, forward, orchestrator, events, rhai, control, logging. A non-empty overlay data_sources list replaces the file-layer list.
Sparse patches that omit a top-level key leave that file-layer section unchanged.
Deep merge surfaces
| Surface | Strategy | Summary |
|---|---|---|
metrics |
Deep merge | Nested maps merge by key; see Metrics deep merge |
pools |
Match-by-name (related pattern) | Pools by name; backends by name or address — see Configuration model — pools |
rules and tracing remain file-layer only — overlays that include those keys are rejected.
Metrics deep merge
When the overlay includes metrics::
| Field | Merge rule |
|---|---|
Scalars (enabled, base, profile, …) |
Overlay wins when set / non-empty |
Nested maps (collection, granularity.overrides, OTEL attrs/headers, …) |
Deep-merge by key; overlay values win per key |
categories.include / categories.exclude |
List replace when that key is present in the patch |
user_metrics |
Match-by-name: update matching entries; append new names |
prometheus / otel |
Nested deep merge (address/path/endpoint and related fields) |
Plan knobs (base, categories, collection, granularity, user metrics, event_export) apply on snapshot swap without restart. Changing Prometheus listen settings hot-rebinds; bind failure rejects the apply. Details: Metrics configurability — Overlay and live apply.
Example — exclude timing without rewriting the whole metrics block:
schema_version: 1
metrics:
categories:
exclude: [timing]
conduitctl apply --file metrics-exclude-timing.yaml
Examples
A complete overlay document
An overlay is ordinary Conduit YAML with schema_version and only the top-level keys you intend to change. Omitted keys leave the file layer alone. Here a single apply lowers one backend’s weight and raises orchestrator retry budget:
schema_version: 1
pools:
- name: default
backends:
- address: "10.0.0.1:53"
weight: 10
orchestrator:
max_attempts: 5
max_txn_duration_ms: 8000
txn_table_capacity: 2048
conduitctl apply --file maintenance-overlay.yaml
pools uses match-by-name (only the listed backend fields update). orchestrator is section replace — the overlay must carry every orchestrator field you want to keep from the file layer (see below). Confirm with conduitctl export. Drop the overlay later with conduitctl apply --clear or reload from disk.
Unintentional clobber (section replace)
Suppose the on-disk file already tunes more than retry count:
# fragment of the file layer
orchestrator:
max_attempts: 3
max_txn_duration_ms: 8000
txn_table_capacity: 2048
An operator who only wants a higher retry count might apply:
schema_version: 1
orchestrator:
max_attempts: 5
Because orchestrator is section replace, that patch becomes the entire effective orchestrator block. max_txn_duration_ms and txn_table_capacity fall back to built-in defaults (5000 and 1024), not the file-layer values — even though those keys were never mentioned in the patch.
The same trap applies to other section-replace surfaces (listeners, forward, events, rhai, control, logging, and a non-empty data_sources list). Sparse patches are safe only when omitting a top-level key; within a replaced section, omitted nested keys are not “keep file.”
Augment a section safely (export, mutate, apply)
For section-replace topics, treat the overlay section as a full replacement: start from what is already effective, change only what you need, and send the whole section back.
1 — Export the running effective config:
conduitctl export --output /tmp/conduit-effective.yaml
2 — Copy the section you will change (here orchestrator:) into a new patch file. Keep schema_version: 1. Leave every other top-level key out of the patch so those file-layer sections stay untouched.
3 — Edit only the fields you intend to change, leaving the rest of the section as exported:
schema_version: 1
orchestrator:
max_attempts: 5 # raised
max_txn_duration_ms: 8000
txn_table_capacity: 2048
4 — Apply and verify:
conduitctl apply --file orchestrator-augmented.yaml
conduitctl export | grep -A5 '^orchestrator:'
Export may omit fields that equal built-in defaults — that is normal normalization, not a missing setting. See Reload and export — export.
metrics is the usual exception: deep merge lets you send a sparse nested patch (as in Metrics deep merge) without rewriting sibling maps. pools patches update matched pools/backends without replacing the whole list.
Choosing a strategy as an operator
- Prefer sparse overlays that only set the top-level keys you intend to change.
- For section-replace topics, include the full section you want effective — use export, mutate, apply when augmenting an existing section. Missing nested keys are not “keep file.”
- For
metrics, nested maps keep file-layer siblings; lists undercategoriesreplace only when you send that list key. - For
pools, match-by-name patches can stay sparse at the backend field level; see Configuration model — pools. Useremove: trueto delete a matched pool or backend (Remove marker).