TopFlow
LearnBuildSecurity
Workflow EndpointP0 - Critical

End Node

Mark the successful completion of your workflow and optionally specify final output values. Every workflow requires at least one End node to signal that execution finished successfully.

Required Node: Every workflow must have at least one End node. When workflow execution reaches an End node, it completes successfully and returns the specified output (or the last computed value).

Overview

The End node marks the successful completion of a workflow. When execution reaches an End node, the workflow stops and returns the final output. End nodes are the counterpart to Start nodes - every workflow path that begins with a Start node should eventually reach an End node.

Unlike most nodes that transform or process data, the End node's primary purpose is to signal completion and optionally specify what data should be returned as the workflow's final result.

Common Use Cases
1
Simple Completion - Mark workflow completion without specifying output (returns last computed value)
2
Explicit Output - Specify exactly what data should be returned (e.g., a success message or structured result)
3
Multi-Path Workflows - Each conditional branch ends with its own End node, returning different results
4
Status Reporting - Return workflow execution status and summary information to calling systems

Configuration

Optional Parameters
The End node has no required configuration - it works by default
outputstringOptional

Explicit output value to return when workflow completes. If not specified, the End node returns the output from the last executed upstream node. Supports variable interpolation ($input1, $input2).

Tip: Leave output empty for simple workflows. Use explicit output when you need to return a specific message (e.g., "Workflow completed successfully" or structured JSON).
Example Output Values:
// Simple success message
"Workflow completed successfully"

// Include data from upstream node
"Security analysis complete: $input1"

// Structured JSON output
{
  "status": "completed",
  "result": "$input1",
  "timestamp": "2026-01-11T18:15:25.739Z"
}

Node Data Interface

TypeScript interface defining the End node's configuration and execution state:

export type EndNodeData = {
  // Configuration
  output?: string  // Optional explicit output value (supports variable interpolation)

  // Execution state (managed by system)
  status?: "idle" | "running" | "completed" | "error"
  finalOutput?: any  // The actual value returned by the workflow
  error?: string
}

Usage Examples

Example 1: Simple Completion (No Output Specified)
Return the last computed value automatically
Workflow Structure:
[Start Node]
       ↓
[HTTP Request] ← Fetch threat data
       ↓
[Text Model] ← Analyze threats
       ↓
[End Node] ← No output specified
End Node Configuration:
output: (empty)
Returned Value:

The workflow returns the output from the Text Model node (the last executed node before End).

"Analysis complete: 2 critical vulnerabilities detected requiring immediate patching.
Systems affected: web-server-01, api-gateway."
Example 2: Explicit Success Message
Return a custom completion message
Workflow Structure:
[Start Node]
       ↓
[HTTP Request] ← Create ticket
       ↓
[End Node] ← Custom success message
End Node Configuration:
output: "Incident ticket created successfully. Ticket ID: $input1.data.result.number"
Returned Value:
"Incident ticket created successfully. Ticket ID: INC0012345"
Example 3: Structured JSON Output
Return comprehensive workflow results
Workflow Structure:
[Start Node]
       ↓
[HTTP Request] ← Fetch threats
       ↓
[JavaScript] ← Calculate severity
       ↓
[Text Model] ← Generate summary
       ↓
[End Node] ← Structured output
End Node Configuration:
output: {
  "status": "completed",
  "severity_score": "$input2.score",
  "severity_level": "$input2.severity",
  "summary": "$input3",
  "timestamp": "2026-01-11T18:15:25.739Z",
  "requires_action": "$input2.requires_immediate_action"
}
Returned Value:
{
  "status": "completed",
  "severity_score": 75,
  "severity_level": "CRITICAL",
  "summary": "2 critical vulnerabilities detected requiring immediate attention",
  "timestamp": "2024-01-15T10:30:00.000Z",
  "requires_action": true
}
Example 4: Multi-Path Workflow (Multiple End Nodes)
Different end nodes for different conditional paths
Workflow Structure:
[Start Node]
       ↓
[HTTP Request] ← Check API
       ↓
[Conditional] ← status === 200?
       ↓            ↓
    TRUE          FALSE
       ↓            ↓
[Process Data]  [Slack Alert]
       ↓            ↓
[End: Success]  [End: Failure]
End Node Configurations:
// Success path End node
output: {
  "status": "success",
  "message": "Data processed successfully",
  "result": "$input1"
}

// Failure path End node
output: {
  "status": "error",
  "message": "API request failed",
  "http_status": "$input1.status",
  "error_details": "$input1.statusText"
}
Returned Values:
  • Success path: Returns success status with processed data
  • Failure path: Returns error status with failure details

Validation Rules

The End node is validated before execution. Validation errors will block workflow execution.

Errors (Block Execution)
✕No End node in workflow (workflow must have at least one End node)
✕End node has outgoing connections (End nodes cannot connect to other nodes)
✕Output references undefined input variables (e.g., $input3 with only 2 upstream nodes)
Warnings (Don't Block)
⚠End node has no incoming connections (unreachable end node - will never execute)
⚠Multiple End nodes with same output value (might be intentional, but could indicate duplicate logic)
⚠Very long output string (consider using upstream JavaScript node to format data)

Code Generation

When you export your workflow to TypeScript code, the End node generates a return statement with the final output:

Generated Code (Workflow Function Export)
export async function runAgentWorkflow(initialInput?: string) {
  // Start Node
  const start_input = initialInput || ""

  // HTTP Request Node
  const node_httpRequest1 = await fetch("https://api.example.com/threats", {
    method: "GET",
    headers: { "Authorization": `Bearer ${process.env.API_KEY}` }
  })
  const httpRequest1_result = await node_httpRequest1.json()

  // Text Model Node
  const node_textModel1 = await generateText({
    model: openai("gpt-4"),
    prompt: `Analyze these threats: ${JSON.stringify(httpRequest1_result)}`
  })

  // End Node - Return final output
  return {
    status: "completed",
    result: node_textModel1.text,
    timestamp: new Date().toISOString()
  }
}
Generated Code (Route Handler Export)
export async function POST(req: Request) {
  try {
    // Parse request body
    const { input } = await req.json()

    // Start Node
    const start_input = input || ""

    // HTTP Request Node
    const node_httpRequest1 = await fetch("https://api.example.com/threats", {
      method: "GET",
      headers: { "Authorization": `Bearer ${process.env.API_KEY}` }
    })

    if (!node_httpRequest1.ok) {
      return Response.json(
        { error: "HTTP request failed" },
        { status: 500 }
      )
    }

    const httpRequest1_result = await node_httpRequest1.json()

    // Text Model Node
    const node_textModel1 = await generateText({
      model: openai("gpt-4"),
      prompt: `Analyze these threats: ${JSON.stringify(httpRequest1_result)}`
    })

    // End Node - Return successful response
    return Response.json({
      status: "completed",
      result: node_textModel1.text,
      timestamp: new Date().toISOString()
    })
  } catch (error) {
    return Response.json(
      { error: `Workflow failed: ${error.message}` },
      { status: 500 }
    )
  }
}

Best Practices

Do
✓Always include at least one End node - Every workflow must have a completion point
✓Use explicit output for API routes - Return structured JSON with status, result, and metadata
✓Use multiple End nodes for conditional workflows - Different branches can return different results
✓Keep output simple when possible - Let the last node's output flow through naturally
✓Include timestamps in output - Helps with debugging and audit trails
Don't
✕Don't connect End nodes to other nodes - End nodes mark completion; they cannot have outgoing connections
✕Don't create unreachable End nodes - Every End node should be reachable from Start node
✕Don't use complex logic in output - Use a JavaScript node before End for complex formatting
✕Don't forget to test all End nodes - In conditional workflows, ensure every path reaches an End

Related Nodes

Start Node

The counterpart to End nodes. Every workflow begins with a Start node and ends with an End node.

View docs
Conditional Node

Branch workflows into multiple paths, each ending with its own End node returning different results.

View docs
JavaScript Node

Format complex output data before the End node. Use JavaScript to structure the final response.

View docs
Next Steps
Start Node Documentation

Learn about the Start node, which pairs with End nodes to define workflow boundaries

Workflows 101

Understand workflow execution flow and how End nodes complete execution

Workflow Patterns

See common patterns for structuring workflows with multiple End nodes