Settings Bindings
A settings binding lets an app setting override a field on a resource that the same app provides. The app stays fully declarative — the literal value in h_app.yaml is the default — while tenant administrators configure deployment-specific values through the standard App Settings UI.
The rule is simple:
- Setting configured → the setting's value overlays the bound field.
- Setting unset → the literal value from
h_app.yamlstays in place.
There is no runtime wiring to build: components never read the setting, and the resource never embeds a registry reference. The platform resolves the effective resource, so connections and ingresses run with the configured values automatically.
When to use bindings
Reach for bindings when your app ships a connection or ingress whose endpoint, address, or credentials differ per tenant or per environment:
- Your app declares
partner-rabbitas a RabbitMQ connection with a literal default endpoint. - Each tenant's administrator points it at their own broker and password in the app's settings page.
- The connection re-establishes itself with the new values.
Do not use bindings for values your Filtrera components read and interpret in code — declare a plain app setting and read it from the registry instead. Bindings are for fields the platform itself consumes to run the resource.
Declaring bindings
Bindings are declared on the setting, under bindings: — the family (connections or ingresses), keyed by the resource's app-local id, with the target field as a simplified JSONPath:
id: amqp-app
name: AMQP app
connections:
partner-rabbit:
type: rabbitmq
properties:
protocol: amqp10
endpoint: amqp://localhost:5672
authentication:
mechanism: plain
username: integration
ingresses:
inbound-orders:
componentId: ingresses/inbound-orders.hrc
type: queue
properties:
address: inbound-orders
settings:
amqpEndpoint:
label:
default: AMQP endpoint
editor: { type: text, order: 10, set: connection }
bindings:
connections:
partner-rabbit: $.properties.endpoint
amqpPassword:
label:
default: AMQP password
secret: true
editor: { type: text, order: 30, set: connection }
bindings:
connections:
partner-rabbit: $.properties.authentication.password
inboundOrdersAddress:
label:
default: Inbound orders address
editor: { type: text, order: 40, set: connection }
bindings:
ingresses:
inbound-orders: $.properties.addressWith no values configured, all three resources run with their literal defaults. The moment an administrator sets amqpEndpoint, the connection reconciles with that endpoint.
One setting, several targets
A setting may bind multiple resources — list each target under the family:
settings:
endpoint:
label:
default: Endpoint
editor: { type: text }
bindings:
connections:
primary: $.properties.endpoint
secondary: $.properties.endpointOne target, several fields
A single resource may receive several fields from one setting — use a list of paths:
settings:
brokerDefaults:
label:
default: Broker defaults
editor: { type: text }
bindings:
connections:
partner-rabbit:
- $.properties.reconnect.initialDelaySeconds
- $.properties.reconnect.maxDelaySecondsTarget paths
Binding targets use a simplified JSONPath over the resource object. The path must select exactly one writable field:
$.properties.endpoint
$.properties.authentication.password
$['properties']['endpoint']Not supported — and rejected at validation time:
- Wildcards (
$.properties.*), filters, and multi-select - Recursive descent (
$..endpoint) - Functions and expressions
- Array addressing (
$.properties.routes[0])
Two rules bound what a path may select:
- Only
propertiesfields are writable for the supported families. A binding must start with$.properties.— the resource'sid,type,componentId, andaclcannot be changed through a setting (changing the adapter type or the ACL through configuration would be unsafe). - The leaf may be absent. Every intermediate object must exist, but the final field can be missing from the manifest — the overlay creates it once the setting is configured. This is the intended pattern for credentials: declare
authentication: { mechanism: plain, username: integration }and bind the password field without a literal default.
Field names match case-insensitively when no exact match exists, so paths can be written in the same casing as the manifest even when the runtime normalizes some ingress fields to a different casing.
Runtime behavior
Resource reads and resource runtimes both use the effective resource — the manifest literal overlaid with every configured bound setting:
GET /resources/connections/{id}and the connections list return effective values.- The connection manager and the ingress runtimes reconcile with effective values.
A settings update commits first; the affected resources then reconcile from the complete committed state. A stateful resource like a connection never applies partial intermediate values: the manager establishes and validates a replacement before retiring the active instance. If a configured value is invalid — say, a malformed endpoint — the previous connection keeps serving traffic (last-known-good) and a reconciliation signal explains the failure instead.
Security
Bound settings follow the same rules as all app settings, plus one:
- Secrets stay write-only. A setting declared
secret: trueis never readable through the settings UI or API, regardless of bindings. - Secret-bound fields are masked in resource reads. Reading a connection whose password field is bound to a secret setting shows
truein place of the value — the same "set" marker the settings API uses. The resolved value never appears in resource reads, audit records, signals, dev-session output, or traffic logs. - Bindings do not grant access. Resource reads keep their existing authorization (
connections/{id}:readetc.). A reader sees effective values only for resources they can already read. - Components need no extra permission. The overlay is applied by the platform, not by component code — unlike a Filtrera component that reads a setting from the registry, a bound resource involves no registry read and needs no registry ACL grant.
In the app's settings page, a bound setting shows which resources it affects (for example, Affects: connections/partner-rabbit) — metadata only, never secret values.
Validation
h_ app pack, app installation, and development mode all validate bindings with the same rules:
- The family is supported:
connectionsoringresses. - The target resource exists in the same app.
- The path uses the supported JSONPath subset and resolves to a single writable field.
- The path does not select an identity field or a field outside
properties. - No two settings target the same field on the same resource.
Errors name both the setting and the target — for example:
Setting 'amqpEndpoint' binds connections/no-such-broker:$.properties.endpoint,
but the app provides no such resourceSetting 'endpoint' binds connections/partner-rabbit:$.properties.endpoint,
which is already bound by setting 'amqpEndpoint'TIP
The editor does not yet report binding diagnostics while you type h_app.yaml — run h_ app pack or start h_ app dev to see validation errors.
Related
- App Configuration Model → App Settings — the settings declaration itself
- Connections — the first resource family with bindable fields
- Ingresses — queue and stream ingress properties
- Registry — where setting values live
- Packaging & Deployment — where validation runs