Skip to main content
A node is the unit of work in a workflow. Every node implements the workflow.Node interface:
  • Type() returns the node’s kind (a NodeType string). Embedding workflow.BaseNode supplies this for you.
  • Validate() runs at compile time. Return an error to reject a misconfigured node before the workflow ever runs.
  • Execute() runs at run time. It returns a partial state update, the output port to follow, and an error.

A basic node

Embed BaseNode to get Type(), then implement Validate and Execute:
Capture host dependencies (DB handles, HTTP clients, API clients) on the node struct via its constructor. The workflow.NodeFactory type — func() (Node, error) — is provided for hosts that build nodes lazily.

Reading run state

All nodes share a single Input. Its RunContext is an opaque map[string]any that accumulates as the run progresses. Read from it in two ways:
  • workflow.ResolvePath(in, "a.b.c") — walk a dotted path into nested maps. Returns (value, ok).
  • in.RunContext["key"] — direct access to a top-level key.

Writing run state

The map you return from Execute is deep-merged into RunContext: keys that hold maps on both sides merge recursively, and all other values replace (last writer wins at the leaves). You only return what changed — never the whole context.
Because independent nodes in the same wave run concurrently, prefer writing to distinct keys per node to avoid one node’s update clobbering another’s.

Output ports

The second return value of Execute is the port — the named output the engine follows to pick the next node. Return workflow.DefaultPort ("default") for linear flow, or a custom port name to branch:
Wire each port to its target with AddEdgeOnPort. A port with no matching edge simply ends that branch.

Typed inputs and outputs

Working with map[string]any everywhere is error-prone. The package provides generic helpers to round-trip between the wire format and your own structs via JSON:
  • DecodeInput[T](map[string]any) (*T, error) — unmarshal the run context (or any map) into a typed struct.
  • EncodeOutput[T](*T) (map[string]any, error) — marshal a typed result back into the map[string]any every node returns.

Pausing instead of completing

A node can suspend the entire run instead of returning output — for example, to wait on a human approval. Return workflow.Pause(payload) from Execute; the run stops cleanly with its state preserved. See Pausing & Resuming for the full flow.