Bindings
Dart workflows pass typed values through codecs. JSON workflows select data with bindings. The two solve different problems and must not be mixed.
Codecs
PayloadCodec<T> converts a typed Dart value to and from durable JSON. Use Codec.identity<T>() only for values already supported by JSON. The runtime never stores a Dart object.
Binding Context
JSON bindings evaluate against a stable context:
| Path | Meaning |
|---|---|
$.input | Workflow input |
$.steps.<stepId>.output | Published step output |
$.result | Current task result while evaluating outputBinding |
$.item | Current forEach item |
Supported JSONPath: root, properties, quoted properties, array indexes, and wildcards. Filters, scripts, recursive descent, and functions are rejected. A missing path fails the decision instead of producing null.
| JSON value | Meaning |
|---|---|
"$.input.orderId" | Read a value |
"$$amount" | The literal string $amount |
"approved", 42, true, null | A literal |
| object or array | Recursively evaluate nested values |
Downstream Visibility
Downstream steps observe the published outputBinding, not hidden handler fields. Bindings are deterministic over workflow input and recorded step results.
Dart Data Flow
In Dart, return values from durable awaits. Do not write through a shared mutable map. Branch scopes receive their own WorkflowContext; results join as a typed map of branch names to values.
final checks = await workflow.parallel(
id: 'checks',
branches: {
'risk': (branch) => branch.serviceTask(riskCheck, order, id: 'risk'),
'credit': (branch) => branch.serviceTask(creditCheck, order, id: 'credit'),
},
);