Skip to main content
A data accessor lets a flow read your module’s data without ever copying it into session state. The flow asks for module.hr.department; the engine resolves it through the accessor registered under the namespace hr.

The contract

Register it from your service provider:

Why this exists

A condition node must never read module tables directly.
If HR data were read straight from its tables by the flow engine, the engine would have to know the module’s schema — and every schema change would become a flow engine change. If it were copied into session state instead, every running session would carry a snapshot that was correct when the session started and wrong an hour later. Resolving through an accessor avoids both. The module stays the single source of truth, the engine stays ignorant of its tables, and the flow always sees current data.

Implementation notes

Return scalars or null. The accessor sits on a boundary that has to serialise; returning an object pushes your internal shape into the engine. supportedKeys() is validation, not documentation. It is used when a flow is saved, so a flow referencing a key you do not support fails at authoring time rather than mid-conversation. Keep it accurate. get() is called during execution. It is on the hot path for any flow that branches on your data. Keep it cheap, and remember it receives the contact and tenant it is being asked about — it must not read anything outside that tenant. The accessor belongs to the module, not to Core. Core provides the registry; you provide the answer. See also State namespaces for how module.* differs from the namespaces a handler may write.