Skip to main content
Edges define the flow of a workflow. The engine starts at the graph’s roots and follows edges from each node’s output port to the next node, running independent branches concurrently.

Static edges and ports

The simplest edge connects a node’s default port to another node:
  • AddEdge(src, dst) wires src’s default port to dst.
  • AddEdgeOnPort(src, port, dst) wires a named output port to dst — use this when a node returns a custom port to branch.

START and END

workflow.StartNode ("START") and workflow.EndNode ("END") are reserved, implicit ids — you never AddNode them. Edges from START mark a graph’s entry points; edges to END terminate a branch. If you don’t wire any START edges, the engine treats every node with no incoming edge as a root. Wiring START explicitly is clearer and lets you choose the entry points yourself.

Parallel execution

The engine runs in waves: all ready nodes in a wave execute concurrently (one goroutine per node), and the next wave begins once they finish. Fan a node out to several successors and they run in parallel; fan them back into a shared node and it runs once, after all its predecessors complete.
Because parallel nodes share one Input, have each write to distinct RunContext keys so their updates don’t clobber one another.

Conditional edges

Static ports branch on a value the node itself chose. Conditional edges decide the next node at runtime by inspecting the accumulated state, without the node knowing about routing:
The routerfunc(in *Input) string — runs after the node completes and returns a label. The engine resolves that label against the targets map to pick the next node. A label that isn’t in the map, or one mapped to workflow.EndNode, ends the branch.
A node may have either static edges or a conditional edge, not both — Compile rejects a node that has both. The router targets must be known node ids or END (they cannot target START).

Boolean expressions

For simple comparisons inside a router, the workflow/expr helper evaluates a minimal boolean expression:
It supports the operators ==, !=, >, <, >=, <=. Operands compare numerically when both parse as numbers, otherwise as strings. With no operator, any non-empty value other than "0" or "false" is truthy. There is no quoting, logical &&/||, or parentheses — build those with regular Go in your router.

Validation

Edges are validated when you Compile the graph. The compiler reports, as a single joined error:
  • Edges referencing an unknown from/to node.
  • Using START or END as a registered node id (they’re reserved).
  • A node that has both static and conditional edges.
  • A conditional target that isn’t a known node or END.
  • Cycles — the graph must be acyclic; a back-edge is reported with the offending path.
See Running Workflows for how to surface these errors.