Portal Community

Config Schema

{
  "targetProcessId": "proc-approval-v2",
  "targetThreadId": "main",
  "mode": "sync",
  "timeout": 300,
  "inputMap": {
    "employeeId": "$output.fetchEmployee.employeeId",
    "requestedAmount": "$output.parseRequest.amount",
    "requestedBy": "$context.actorId"
  },
  "outputMap": {
    "approvalDecision": "$.finalNode.decision",
    "approvedBy": "$.finalNode.approverName"
  }
}

Config Fields

FieldTypeDescription
targetProcessIdstringID of the target workflow process to invoke
targetThreadIdstringThread within the process (default: "main")
mode"sync" | "async"Sync: parent waits; async: fire-and-forget
timeoutnumber (seconds)Sync mode only — how long to wait before timeout port fires
inputMapobjectKey-value pairs: child input field name → parent expression
outputMapobjectKey-value pairs: parent variable name → child output expression

Backend Executor

// ExecutionNodes/SubWorkflow/SubWorkflowExecutor.cs
public class SubWorkflowExecutor : BaseNodeExecutor
{
    private readonly ISubWorkflowInvoker _invoker;

    public SubWorkflowExecutor(ISubWorkflowInvoker invoker)
    {
        _invoker = invoker;
    }

    public override async Task<NodeExecutionResult> ExecuteAsync(NodeExecutionContext ctx)
    {
        var config = ctx.GetConfig<SubWorkflowConfig>();

        // Evaluate inputMap expressions to build child trigger data
        var childInput = EvaluateInputMap(config.InputMap, ctx.ExpressionContext);

        var result = await _invoker.InvokeAsync(new SubWorkflowRequest
        {
            TargetProcessId = config.TargetProcessId,
            TargetThreadId = config.TargetThreadId ?? "main",
            Mode = config.Mode,
            TriggerData = childInput,
            ParentExecutionId = ctx.ExecutionId,
            TimeoutSeconds = config.Timeout
        }, ctx.CancellationToken);

        if (config.Mode == InvocationMode.Async)
        {
            // Fire-and-forget: return child executionId only
            return NodeExecutionResult.Success(new { childExecutionId = result.ExecutionId });
        }

        // Sync: map child output back to parent
        var parentOutput = EvaluateOutputMap(config.OutputMap, result.FinalOutput);
        return NodeExecutionResult.Success(parentOutput);
    }
}

Node Output Shape

ModeOutput
SynchronousResult of evaluating outputMap against child's final node output
Asynchronous{ childExecutionId: "exec-101" }
Process picker UI: In the Flow Studio designer, the SubWorkflow node config panel shows a searchable dropdown of all published processes in your tenant. Select the target process and the designer auto-populates the targetProcessId field.