Branch your workflow based on conditions. Evaluate JavaScript expressions to route execution down one of two paths (true or false), enabling dynamic workflows that adapt to data.
true, and one for when it's false. Only the matching path executes.The Conditional node enables dynamic workflow routing based on data from upstream nodes. It evaluates a JavaScript expression and directs execution down either the "true" path or the "false" path, similar to an if/else statement in programming.
conditionstringJavaScript expression that evaluates to a boolean value (true or false). Inputs from upstream nodes are available as variables: input1, input2, input3, etc.
// Check HTTP status code
input1.status === 200
// Check severity level
input1.severity === "CRITICAL" || input1.severity === "HIGH"
// Check threshold
JSON.parse(input1).score > 50
// Check if data exists
input1 && input1.length > 0
// Complex condition
input1.status === 200 && input1.data.threats.length > 0Unlike other nodes that have a single output handle, the Conditional node has two:
Downstream nodes connected to this handle execute when the condition evaluates to true. In the generated code, this path is inside the if block.
Downstream nodes connected to this handle execute when the condition evaluates to false. In the generated code, this path is inside the else block.
true, the false path is completely skipped (and vice versa). This is different from parallel execution where both paths would run.[Text Model Node]
↓
[JavaScript Node] ← Calculate severity score
↓
[Conditional Node] ← Check if score >= 50
↓ ↓
TRUE FALSE
↓ ↓
[PagerDuty] [Slack]
(Alert) (Notify)input1.score >= 50input1.score = 75 → Condition is true → PagerDuty node executes → Slack node is skippedinput1.score = 30 → Condition is false → Slack node executes → PagerDuty node is skippedTypeScript interface defining the Conditional node's configuration and execution state:
export type ConditionalNodeData = {
// Configuration
condition: string // JavaScript expression that evaluates to boolean
// Execution state (managed by system)
status?: "idle" | "running" | "completed" | "error"
output?: boolean // Result of condition evaluation (true or false)
error?: string
}HTTP Request node calls external API. Route to success handler if status is 200, otherwise route to error notification.
{
"status": 200,
"statusText": "OK",
"data": { "threats": [...] }
}input1.status === 200[HTTP Request]
↓
[Conditional: status === 200]
↓ ↓
TRUE FALSE
↓ ↓
[Process Data] [Slack Alert]
"API Failed"Status 200 → TRUE path → Process data normally
Status 500/404/etc. → FALSE path → Send Slack alert about API failure
Security analysis produces severity rating. Critical and high-severity incidents go to PagerDuty (immediate response), medium and low go to Slack (monitoring only).
{
"severity": "CRITICAL",
"score": 85,
"requires_immediate_action": true,
"threat_summary": "2 critical vulnerabilities detected"
}input1.severity === "CRITICAL" || input1.severity === "HIGH"[Text Model: Analyze]
↓
[JavaScript: Calculate Score]
↓
[Conditional: CRITICAL or HIGH?]
↓ ↓
TRUE FALSE
↓ ↓
[PagerDuty] [Slack]
(Page SOC) (Notify Team)CRITICAL or HIGH → TRUE path → Create PagerDuty incident (wakes up on-call engineer)
MEDIUM or LOW → FALSE path → Post to Slack channel (team reviews during business hours)
Calculate threat count from security logs. If count exceeds threshold (10 threats), trigger full investigation workflow. Otherwise, just log for review.
{
"threat_count": 15,
"critical": 3,
"high": 12
}input1.threat_count > 10[HTTP: Fetch Threats]
↓
[JavaScript: Count Threats]
↓
[Conditional: count > 10?]
↓ ↓
TRUE FALSE
↓ ↓
[Investigation] [Log to Splunk]
↓
[Create Ticket]
↓
[Notify SOC]Count > 10 → TRUE path → Full investigation (ticket + SOC notification + detailed analysis)
Count ≤ 10 → FALSE path → Simple logging to Splunk for later review
API might return empty data. Validate that threat data exists before processing, otherwise skip processing and send "no threats detected" message.
{
"status": 200,
"data": {
"threats": [] // Empty array - no threats
}
}input1.data.threats && input1.data.threats.length > 0[HTTP: Fetch Threats]
↓
[Conditional: threats exist?]
↓ ↓
TRUE FALSE
↓ ↓
[Analyze Threats] [Slack]
↓ "All clear - no threats"
[Generate Report]Threats exist → TRUE path → Process threats, analyze, generate report
No threats → FALSE path → Send "all clear" message to Slack
External API returns 429 (rate limit exceeded). Route to retry logic with exponential backoff instead of failing immediately.
{
"status": 429,
"statusText": "Too Many Requests",
"data": {
"error": "Rate limit exceeded. Retry after 60 seconds."
}
}input1.status === 429[HTTP Request]
↓
[Conditional: status === 429?]
↓ ↓
TRUE FALSE
↓ ↓
[JavaScript] [Conditional]
"Wait 60s" [status === 200?]
↓ ↓
[HTTP Retry] [Process]Status 429 → TRUE path → Implement retry logic with delay
Status 200/other → FALSE path → Continue normal processing or error handling
The Conditional node is validated before execution. Validation errors will block workflow execution.
conditioninput3 with only 2 connections)true or 1 === 1)When you export your workflow to TypeScript code, the Conditional node generates standard if/else blocks:
// Conditional Node: Check severity level
const condition_conditional1 = input1.severity === "CRITICAL" || input1.severity === "HIGH"
if (condition_conditional1) {
// TRUE path - nodes connected to true output handle
// PagerDuty alert
const node_httpRequest1 = await fetch("https://api.pagerduty.com/incidents", {
method: "POST",
headers: {
"Authorization": "Token token=YOUR_TOKEN",
"Content-Type": "application/json"
},
body: JSON.stringify({
incident: {
title: `Critical Security Alert: ${input1.threat_summary}`,
urgency: "high"
}
})
})
const httpRequest1_result = await node_httpRequest1.json()
} else {
// FALSE path - nodes connected to false output handle
// Slack notification
const node_httpRequest2 = await fetch("https://hooks.slack.com/services/YOUR/WEBHOOK", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
text: `Security notification: ${input1.threat_summary}`
})
})
const httpRequest2_result = await node_httpRequest2.json()
}export async function POST(req: Request) {
// ... previous nodes ...
// Conditional Node: Check severity level
const condition_conditional1 = node_javascript1.severity === "CRITICAL" || node_javascript1.severity === "HIGH"
if (condition_conditional1) {
// TRUE path execution
try {
const node_httpRequest1 = await fetch("https://api.pagerduty.com/incidents", {
method: "POST",
headers: {
"Authorization": `Token token=${process.env.PAGERDUTY_TOKEN}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
incident: {
title: `Critical Security Alert: ${node_javascript1.threat_summary}`,
urgency: "high"
}
})
})
if (!node_httpRequest1.ok) {
return Response.json(
{ error: "PagerDuty alert failed" },
{ status: 500 }
)
}
const httpRequest1_result = await node_httpRequest1.json()
return Response.json({
success: true,
outputs: {
conditional1: true,
httpRequest1: httpRequest1_result
}
})
} catch (error) {
return Response.json(
{ error: `True path failed: ${error.message}` },
{ status: 500 }
)
}
} else {
// FALSE path execution
try {
const node_httpRequest2 = await fetch("https://hooks.slack.com/services/YOUR/WEBHOOK", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
text: `Security notification: ${node_javascript1.threat_summary}`
})
})
const httpRequest2_result = await node_httpRequest2.json()
return Response.json({
success: true,
outputs: {
conditional1: false,
httpRequest2: httpRequest2_result
}
})
} catch (error) {
return Response.json(
{ error: `False path failed: ${error.message}` },
{ status: 500 }
)
}
}
}input1.status === 200 over complex nested logic&& to verify data exists before accessing propertiesinput1.data.field will error if data is undefined=== true)// Success check
input1.status === 200
// Any 2xx status
input1.status >= 200 && input1.status < 300
// Specific error
input1.status === 429 // Rate limit// Safe property access
input1 && input1.data && input1.data.threats.length > 0
// Using optional chaining (modern JS)
input1?.data?.threats?.length > 0// OR conditions (any match)
input1.severity === "CRITICAL" || input1.severity === "HIGH"
// AND conditions (all match)
input1.status === 200 && input1.data.threats.length > 0
// Combined
(input1.severity === "CRITICAL" || input1.severity === "HIGH") && input1.requires_immediate_actionLearn common patterns for conditional branching, error handling, and multi-path workflows
Understand how TopFlow's topological execution handles conditional branching
Use JavaScript to calculate values before branching with Conditional nodes