Skip to content

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.yaml stays 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-rabbit as 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:

yaml
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.address

With 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:

yaml
settings:
  endpoint:
    label:
      default: Endpoint
    editor: { type: text }
    bindings:
      connections:
        primary: $.properties.endpoint
        secondary: $.properties.endpoint

One target, several fields ​

A single resource may receive several fields from one setting — use a list of paths:

yaml
settings:
  brokerDefaults:
    label:
      default: Broker defaults
    editor: { type: text }
    bindings:
      connections:
        partner-rabbit:
          - $.properties.reconnect.initialDelaySeconds
          - $.properties.reconnect.maxDelaySeconds

Target paths ​

Binding targets use a simplified JSONPath over the resource object. The path must select exactly one writable field:

text
$.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:

  1. Only properties fields are writable for the supported families. A binding must start with $.properties. — the resource's id, type, componentId, and acl cannot be changed through a setting (changing the adapter type or the ACL through configuration would be unsafe).
  2. 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: true is 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 true in 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}:read etc.). 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: connections or ingresses.
  • 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:

text
Setting 'amqpEndpoint' binds connections/no-such-broker:$.properties.endpoint,
but the app provides no such resource
text
Setting '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.

© 2026 Hantera AB. Org. no.: 559242-9582