TopFlow
LearnBuildSecurity
Flow ControlP0 - Critical

Conditional Node

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.

Two Output Paths: The Conditional node has two output handles - one for when the condition is true, and one for when it's false. Only the matching path executes.

Overview

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.

Common Use Cases
1
HTTP Status Code Routing - Check if API request succeeded (status 200) or failed, then route to success or error handling paths
2
Severity-Based Alerting - Route high-severity incidents to PagerDuty (immediate alert) and low-severity to Slack (notification only)
3
Threshold Checking - Execute different actions based on numeric thresholds (e.g., threat score > 50)
4
Data Validation - Check if required fields exist or data meets criteria before proceeding with processing
5
A/B Testing - Route workflow execution based on feature flags or experiment conditions
6
Rate Limit Handling - Detect API rate limit errors (429 status) and route to retry logic vs. normal processing

Configuration

Required Parameters
These fields must be configured for the node to execute
conditionstring

JavaScript expression that evaluates to a boolean value (true or false). Inputs from upstream nodes are available as variables: input1, input2, input3, etc.

Tip: The condition must return a boolean. If it returns a non-boolean value, JavaScript's truthy/falsy rules apply (empty strings, 0, null, undefined are falsy; everything else is truthy).
Example Conditions:
// 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 > 0

How Branching Works

Two Output Handles
Understanding true and false paths

Unlike other nodes that have a single output handle, the Conditional node has two:

✓
True Output Handle

Downstream nodes connected to this handle execute when the condition evaluates to true. In the generated code, this path is inside the if block.

✕
False Output Handle

Downstream nodes connected to this handle execute when the condition evaluates to false. In the generated code, this path is inside the else block.

Important: Only one path executes per workflow run. If the condition is true, the false path is completely skipped (and vice versa). This is different from parallel execution where both paths would run.
Visual Example: Severity Routing
Workflow Structure:
[Text Model Node]
       ↓
[JavaScript Node]  ← Calculate severity score
       ↓
[Conditional Node] ← Check if score >= 50
       ↓    ↓
    TRUE   FALSE
       ↓    ↓
[PagerDuty] [Slack]
 (Alert)   (Notify)
Condition:
input1.score >= 50
Execution Flow:
  • If input1.score = 75 → Condition is true → PagerDuty node executes → Slack node is skipped
  • If input1.score = 30 → Condition is false → Slack node executes → PagerDuty node is skipped

Node Data Interface

TypeScript 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
}

Usage Examples

Example 1: HTTP Status Code Routing
Route based on API request success/failure
Scenario:

HTTP Request node calls external API. Route to success handler if status is 200, otherwise route to error notification.

Input (from HTTP Request node):
{
  "status": 200,
  "statusText": "OK",
  "data": { "threats": [...] }
}
Condition:
input1.status === 200
Workflow Structure:
[HTTP Request]
       ↓
[Conditional: status === 200]
       ↓            ↓
    TRUE          FALSE
       ↓            ↓
[Process Data]  [Slack Alert]
                  "API Failed"
Result:

Status 200 → TRUE path → Process data normally
Status 500/404/etc. → FALSE path → Send Slack alert about API failure

Example 2: Severity-Based Alert Routing
Send critical alerts to PagerDuty, others to Slack
Scenario:

Security analysis produces severity rating. Critical and high-severity incidents go to PagerDuty (immediate response), medium and low go to Slack (monitoring only).

Input (from JavaScript node):
{
  "severity": "CRITICAL",
  "score": 85,
  "requires_immediate_action": true,
  "threat_summary": "2 critical vulnerabilities detected"
}
Condition:
input1.severity === "CRITICAL" || input1.severity === "HIGH"
Workflow Structure:
[Text Model: Analyze]
       ↓
[JavaScript: Calculate Score]
       ↓
[Conditional: CRITICAL or HIGH?]
       ↓            ↓
    TRUE          FALSE
       ↓            ↓
[PagerDuty]     [Slack]
 (Page SOC)   (Notify Team)
Result:

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)

Example 3: Threshold-Based Processing
Different actions based on numeric thresholds
Scenario:

Calculate threat count from security logs. If count exceeds threshold (10 threats), trigger full investigation workflow. Otherwise, just log for review.

Input (from JavaScript node):
{
  "threat_count": 15,
  "critical": 3,
  "high": 12
}
Condition:
input1.threat_count > 10
Workflow Structure:
[HTTP: Fetch Threats]
       ↓
[JavaScript: Count Threats]
       ↓
[Conditional: count > 10?]
       ↓              ↓
    TRUE            FALSE
       ↓              ↓
[Investigation]  [Log to Splunk]
  ↓
[Create Ticket]
  ↓
[Notify SOC]
Result:

Count > 10 → TRUE path → Full investigation (ticket + SOC notification + detailed analysis)
Count ≤ 10 → FALSE path → Simple logging to Splunk for later review

Example 4: Data Validation Before Processing
Check if required data exists before continuing
Scenario:

API might return empty data. Validate that threat data exists before processing, otherwise skip processing and send "no threats detected" message.

Input (from HTTP Request node):
{
  "status": 200,
  "data": {
    "threats": []  // Empty array - no threats
  }
}
Condition:
input1.data.threats && input1.data.threats.length > 0
Workflow Structure:
[HTTP: Fetch Threats]
       ↓
[Conditional: threats exist?]
       ↓              ↓
    TRUE            FALSE
       ↓              ↓
[Analyze Threats] [Slack]
  ↓             "All clear - no threats"
[Generate Report]
Result:

Threats exist → TRUE path → Process threats, analyze, generate report
No threats → FALSE path → Send "all clear" message to Slack

Example 5: API Rate Limit Handling
Detect 429 status and route to retry logic
Scenario:

External API returns 429 (rate limit exceeded). Route to retry logic with exponential backoff instead of failing immediately.

Input (from HTTP Request node):
{
  "status": 429,
  "statusText": "Too Many Requests",
  "data": {
    "error": "Rate limit exceeded. Retry after 60 seconds."
  }
}
Condition:
input1.status === 429
Workflow Structure:
[HTTP Request]
       ↓
[Conditional: status === 429?]
       ↓              ↓
    TRUE            FALSE
       ↓              ↓
[JavaScript]   [Conditional]
 "Wait 60s"   [status === 200?]
       ↓              ↓
[HTTP Retry]   [Process]
Result:

Status 429 → TRUE path → Implement retry logic with delay
Status 200/other → FALSE path → Continue normal processing or error handling

Validation Rules

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

Errors (Block Execution)
✕Missing required field: condition
✕Empty condition field (no JavaScript expression provided)
✕Syntax error in condition expression (detected by parser)
✕Condition references undefined input variables (e.g., input3 with only 2 connections)
✕No downstream connections (both true and false paths are empty - node does nothing)
Warnings (Don't Block)
⚠Only true path has downstream connections (false path is empty - might be intentional)
⚠Only false path has downstream connections (true path is empty - might be intentional)
⚠Condition always evaluates to same value (e.g., true or 1 === 1)
⚠Complex condition (very long expression - consider using JavaScript node first)

Code Generation

When you export your workflow to TypeScript code, the Conditional node generates standard if/else blocks:

Generated Code (Workflow Function Export)
// 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()
}
Generated Code (Route Handler Export)
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 }
      )
    }
  }
}

Best Practices

Do
✓Use simple, readable conditions - Prefer input1.status === 200 over complex nested logic
✓Handle both paths - Connect nodes to both true and false outputs unless you intentionally want to skip one path
✓Use JavaScript node for complex logic - Calculate scores/values first, then use simple comparison in Conditional
✓Check for null/undefined - Use && to verify data exists before accessing properties
✓Label your paths clearly - Use descriptive node names on each branch so the workflow is self-documenting
✓Test both paths - Execute workflow with data that triggers both true and false conditions during testing
Don't
✕Don't use overly complex conditions - Break into JavaScript node + Conditional for readability
✕Don't nest multiple Conditionals unnecessarily - Consider using JavaScript node to return categorical result
✕Don't forget to handle null values - input1.data.field will error if data is undefined
✕Don't rely on truthy/falsy behavior for important logic - Use explicit comparisons (=== true)
✕Don't leave both paths empty - A Conditional with no downstream nodes is useless
✕Don't use async operations in conditions - Conditions evaluate synchronously only
Common Condition Patterns
Status Code Checks:
// Success check
input1.status === 200

// Any 2xx status
input1.status >= 200 && input1.status < 300

// Specific error
input1.status === 429  // Rate limit
Null/Undefined Checks:
// Safe property access
input1 && input1.data && input1.data.threats.length > 0

// Using optional chaining (modern JS)
input1?.data?.threats?.length > 0
Multiple Conditions:
// 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_action

Related Nodes

JavaScript Node

Calculate complex values before branching. Use JavaScript node to compute scores, then Conditional to decide the path.

View docs
HTTP Request Node

Call external APIs, then use Conditional to route based on HTTP status codes or response data.

View docs
Text Model Node

Analyze data with AI, then use Conditional to route based on the analysis results (severity, categories, etc.).

View docs
Next Steps
Workflow Patterns

Learn common patterns for conditional branching, error handling, and multi-path workflows

Workflows 101

Understand how TopFlow's topological execution handles conditional branching

JavaScript Node

Use JavaScript to calculate values before branching with Conditional nodes