Config schema: pools
This page lists the fields for the top-level pools: list and each pool / backend object. For behavior — selection, weights, multiple pools, retries — see Pools and backends.
pools
| Property | Value |
|---|---|
| Type | List of pool objects |
| Required | Yes for a runnable installation (forwarding needs at least one pool with backends) |
| Location | Top-level key in the config file |
Each list entry is one named pool. Pool name values must be unique within the file; duplicate names fail validation.
Pool object
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
name | string | yes | — | Identifier referenced by set_pool, set_retry_pool, Rhai set_pool / set_retry_pool, metrics labels, and event filters. Must be non-empty and unique among pools. The name default is a convention for the catch-all pool when nothing else selects a pool — see Default pool selection. |
backends | list | yes | — | One or more backend entries. An empty list fails validation. |
health | object | no | (disabled) | Optional backend health settings for this pool. See Reference: health. |
sources_v4 | list of strings | no | (use forward defaults) | IPv4 addresses to bind when forwarding to this pool’s backends. Overrides global forward.sources_v4 for this pool when non-empty. See Dual-stack forwarding. |
sources_v6 | list of strings | no | (use forward defaults) | IPv6 addresses for upstream egress for this pool. Overrides global forward.sources_v6 when non-empty. |
max_inflight | integer | no | (unlimited) | Optional cap on concurrent in-flight forwards for this pool. When set, must be ≥ 1. Enforced under the split_io runtime; a query that would exceed the cap returns SERVFAIL rather than queueing. See Per-pool in-flight limit. |
Default pool selection
When no rule, Rhai script, or retry has set a pool for the transaction, Conduit picks a pool at Route time:
- If a pool named
defaultexists, use it. - Otherwise use the first pool in the
pools:list (YAML order).
Naming a catch-all pool default is a convention, not a schema requirement — validation does not require that name. If you omit default, list order defines the fallback pool. A pool named default that appears later in the list still wins over earlier pools when fallback applies.
For examples (split horizon, explicit rules vs catch-all), see Pools and backends.
Pool sources_v4 / sources_v6 constraints
- Each entry must be a valid IPv4 or IPv6 address (not
ip:port). - Entries must not be empty strings.
- At most 32 addresses per list (
sources_v4andsources_v6separately). - When a pool list is empty or omitted, Conduit uses the corresponding global
forward.sources_v4orforward.sources_v6list (if any), then system defaults for bind behavior.
Per-pool in-flight limit
max_inflight bounds how many transactions may be forwarding to this pool at once. It is a coarse pool-level guard — distinct from per-backend upstream concurrency (forward.outstanding_per_backend) and the global transaction slot pool (orchestrator.txn_table_capacity).
- Default (unset) — no per-pool cap; pool concurrency is bounded only by the slot pool and per-backend limits.
- Set — when a forward would exceed the cap, Conduit returns SERVFAIL to the client immediately (it does not queue or block). The reserved slot is released when the upstream replies, times out, or errors.
- Runtime scope — enforced under the
split_ioruntime. Undersync, pool concurrency is already bounded by listenerthreads, somax_inflightis validated but not separately enforced.
Backend object
Backends are nested under pools[].backends. Each backend is one upstream resolver. An optional name gives the backend a stable identity for metrics labels and control-plane overlay patches; without it the upstream is identified by address.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
address |
string | yes | — | Upstream resolver as ip:port. IPv6 literals use bracket notation, for example [2001:db8::1]:53. Must parse as a socket address. |
weight |
integer | no | 100 | Load-balancing weight within the pool. If set, must be ≥ 1. Omitted or unset means effective weight 100. |
name |
string | no | (use address) |
Stable identity for this backend. When set, it becomes the backend metric label and the key for overlay patches that target (pool, name). Must be unique within the pool when set. |
probe_qname |
string | no | (pool health template) | Per-backend override for health probe query name when pool health is enabled. |
probe_qtype |
string | no | (pool health template) | Per-backend override for health probe query type. |
probe_source |
string | no | (system bind) | Local IP address to bind for health probes to this backend. |
transport |
string | no | — | Reserved for forward-compatible use; not honored when it diverges from forward.upstream_transport. |
Validation summary
| Rule | Error if violated |
|---|---|
Unique pool name |
duplicate pool name '…' |
Non-empty pool name |
pool name must not be empty |
| Pool has ≥ 1 backend | pool '…' has no backends |
Backend address parses |
pool '…' backend '…': invalid socket address |
Backend weight ≥ 1 when set |
pool '…' backend '…' weight must be >= 1 |
Backend name unique within a pool |
pool '…' duplicate backend name '…' |
Pool max_inflight ≥ 1 when set |
pool '…' max_inflight must be >= 1 when set |
Valid pool sources_v4 / sources_v6 |
pool '…': … (parse/limit messages) |
Validate with conduitctl validate --file … or load via the running process; see Config file.
Reload and restart
Pool routing — backend address, weight, name, pool membership, and sources_v4 / sources_v6 — is hot: a successful reload applies to new queries from the next snapshot, and metric labels follow the new name values.
max_inflight is fixed at process start. A changed value is stored in the new snapshot but the active limit is not re-read until you restart conduit.
Example configuration
pools:
- name: default
sources_v4:
- "10.0.0.10" # Conduit host on the recursor-facing VLAN
backends:
- address: "10.0.0.1:53"
name: resolver-a # stable metrics label + overlay target
weight: 70
- address: "10.0.0.2:53"
name: resolver-b
# weight omitted → 100
- name: internal
max_inflight: 256 # cap concurrent forwards to this pool (split_io)
sources_v4:
- "10.0.1.10" # Conduit host on the internal DNS network
backends:
- address: "10.0.1.53:53"
Related topics
- Pools and backends — behavior and examples
- Rules and actions —
set_pooland selectors - Retries and transactions —
set_retry_pool,retry - Configuration model — overlay patches targeting backends by
(pool, name) - Runtime and concurrency — transaction slot pool and in-flight limits
- Dual-stack forwarding — pool and global egress sources
- Reference: health — pool
health:block and per-backend probe overrides