Flows
The anatomy of a flow file: service, env, connectors, processors, flows, and resources.
An integration is a YAML file (or directory) that declares the connectors it needs and the flows that process messages.
Top-level keys
A config has six top-level keys. Only flows does the actual work.
| Key | What it declares |
|---|---|
service | The integration's identity: name and an optional environment. |
env | Environment variables the config may reference as ${NAME} in settings and as env.NAME in expressions. See Environment and Configuration. |
connectors | Named connector instances (an HTTP server, a database pool, an LLM client). |
processors | Reusable, named block definitions that flow blocks reference with ref:. |
flows | One or more root flows: a source feeding a pipeline of blocks. |
resources | Imported files: .env-convention files and templates. See Resources. |
A complete flow
service:
name: orders # identity; shows up in logs
environment: prod
env:
- name: HTTP_PORT
default: "8080"
connectors:
- name: api # instance name, referenced below
type: http # connector type
settings:
port: ${HTTP_PORT}
processors:
- name: greeter # reusable block definition
type: log
settings:
message: '"got order " + vars.id'
flows:
- name: orders-api
workers: 8 # concurrent workers (default 8)
buffer: 128 # source channel depth (default 64)
source:
connector: api # the *name* of a connector instance
type: http # connector-specific source type
settings:
path: /orders/{id} # {id} -> vars.id
process: # the pipeline, run block by block
- ref: greeter # reference a named processor
- type: set-payload
settings:
value: '{"orderId": vars.id, "status": "accepted"}'
error: # recovery pipeline (root flows only)
- type: set-variable
settings: { name: httpStatus, value: "502" }
- type: set-payload
settings:
value: '{"error": vars.error.message}'Flow fields
| Field | Meaning |
|---|---|
name | The flow's identifier. Sourceless flows are callable by this name (see below). |
source | The entry point. connector names a configured connector instance (not its type), type selects a connector-specific source kind, and settings configures it (a route path, a cron schedule, a queue subject). |
process | The ordered list of blocks each message runs through. |
error | The recovery pipeline. When process fails, the runtime exposes the failure as vars.error and runs this chain; on success its output becomes the flow's result. Root flows only. See Error Handling. |
workers | How many messages the flow processes concurrently. Defaults to 8. |
buffer | The depth of the channel between the source and the workers. Defaults to 64. |
pool | The size of the shared worker pool handed to composites that schedule concurrent work (a fork's branches). Defaults to 8. Root flows only. |
Sub-flows nested inside a composite block (an if's then, a foreach's body) reuse the same shape but must not set source, workers, buffer, pool, or error; the builder rejects it.
Named processors and ref:
A processor is a block definition declared once under processors: and referenced from any flow. The referencing block takes the definition's type and settings and may override settings key by key.
processors:
- name: greeter
type: log
settings:
level: info
message: '"hello world! the date is " + body.date'
flows:
- name: greet
source:
connector: ticker
type: cron
settings:
schedule: "0,30 * * * * *"
payload: '{"date": string(now)}'
process:
- ref: greeterA block sets either ref or type, not both.
Implicit connectors
Connectors with no per-instance configuration (cron, queue, events) need no entry under connectors:. When a source's type names a registered connector type and no instance is configured, the runtime starts a default instance on demand:
flows:
- name: emitter
source:
type: cron # implicit connector: no connectors entry needed
settings:
schedule: "@every 3s"
payload: '{"tick": string(now)}'
process:
- type: publish-event
settings:
subject: '"notifications"'When exactly one connector of the type is configured, a source of that type binds to it implicitly. With several configured you must name one with connector:.
Connectors that carry real configuration (an http server's port, a database DSN, an LLM API key) should be declared explicitly under connectors:.
Sourceless flows
A flow with no source: gets an implicit source and becomes callable by name, from another flow via the flow-ref block or directly from the CLI:
flows:
- name: greet
process:
- type: set-payload
settings:
value: '{"greeting": "hello, " + body.name + "!"}'octo invoke --config hello-invoke.yaml --flow greet --data '{"name":"Ada"}'
# {"event_id":"5c12…","body":{"greeting":"hello, Ada!"}}In invoke mode no sources are started, so only the requested flow runs. Sourceless flows are the building block for reusable sub-pipelines: call them synchronously with flow-ref (the result folds back into the caller's message) or one-way (fire-and-forget).
Next steps
Learn how connectors, blocks, and composites fit together in Connectors and Blocks, or browse the complete catalogue in the Reference.