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.
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.
outputstringOptionalExplicit 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).
// 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"
}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
}[Start Node]
↓
[HTTP Request] ← Fetch threat data
↓
[Text Model] ← Analyze threats
↓
[End Node] ← No output specifiedoutput: (empty)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."[Start Node]
↓
[HTTP Request] ← Create ticket
↓
[End Node] ← Custom success messageoutput: "Incident ticket created successfully. Ticket ID: $input1.data.result.number""Incident ticket created successfully. Ticket ID: INC0012345"[Start Node]
↓
[HTTP Request] ← Fetch threats
↓
[JavaScript] ← Calculate severity
↓
[Text Model] ← Generate summary
↓
[End Node] ← Structured outputoutput: {
"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"
}{
"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
}[Start Node]
↓
[HTTP Request] ← Check API
↓
[Conditional] ← status === 200?
↓ ↓
TRUE FALSE
↓ ↓
[Process Data] [Slack Alert]
↓ ↓
[End: Success] [End: Failure]// 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"
}The End node is validated before execution. Validation errors will block workflow execution.
$input3 with only 2 upstream nodes)When you export your workflow to TypeScript code, the End node generates a return statement with the final output:
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()
}
}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 }
)
}
}Learn about the Start node, which pairs with End nodes to define workflow boundaries
Understand workflow execution flow and how End nodes complete execution
See common patterns for structuring workflows with multiple End nodes