The Output Object
What NodeExecutionResult.Success(output) stores — arbitrary JSON object, storage location in ExecutionMemory, and the pinned data variant.
NodeExecutionResult — The Return Type
Every node executor returns a NodeExecutionResult from its ExecuteAsync method. This result carries both the routing decision (which port fires) and the data payload. The three static factory methods are:
// Happy path — node succeeded, returns data via main port
NodeExecutionResult.Success(object? output, object? pinnedData = null, string portKey = "main")
// Node failed — routes to error port, exception is captured
NodeExecutionResult.Fail(Exception exception)
// Node intentionally produced nothing — null in memory, no routing
NodeExecutionResult.Skip()
What Gets Stored
When Success(output) is called, the engine serializes the output to JSON and stores it at:
ExecutionMemory.nodeOutputs[nodeId] = output
The output parameter is typed as object? — it can be any JSON-serializable type: a plain class, an anonymous object, a dictionary, an array, or even a scalar string or number.
Common Output Shapes
// Returning a typed DTO
return NodeExecutionResult.Success(new InvoiceResult
{
InvoiceId = invoice.Id,
Total = invoice.Total,
Status = invoice.Status
});
// Returning an anonymous object
return NodeExecutionResult.Success(new
{
userId = user.Id,
email = user.Email,
roles = user.Roles
});
// Returning a list
return NodeExecutionResult.Success(new
{
items = queryResults,
rowCount = queryResults.Count
});
// Returning a scalar
return NodeExecutionResult.Success(new { value = 42 });
Pinned Data vs. Live Output
NodeExecutionResult.Success accepts an optional pinnedData parameter. Pinned data is a snapshot stored alongside the live output and displayed in the Node Inspector during execution replay. It does not affect expression evaluation — only output is accessible via $output.{nodeId}.
return NodeExecutionResult.Success(
output: new { orderId = order.Id, status = "created" },
pinnedData: new { rawResponse = httpResponse.Body, elapsedMs = sw.ElapsedMilliseconds }
);
Custom Port Key
By default, Success() fires the "main" port. To route to a custom port, pass the portKey parameter:
// Route to "approved" port
return NodeExecutionResult.Success(new { decision = "approved" }, portKey: "approved");
// Route to "rejected" port
return NodeExecutionResult.Success(new { decision = "rejected", reason = "score too low" }, portKey: "rejected");
Data Persistence
Node outputs are persisted to the database when the execution checkpoints (at each node boundary). This means output is available even after a server restart or during HIL suspension — the full ExecutionMemory is rehydrated from the database when execution resumes.