Ep 06: Branching & Loops — If, Switch, and Loop Nodes Decoded

⏱ Est. reading time: 12 min Updated on 4/9/2026

Why Conditional Control?

All workflows from Episodes 1-5 were linear — data flows straight from start to end. Real business requires "if...then..." decisions:

graph LR
    subgraph "Linear Flow (Ep 01-05)"
        L1[Trigger] --> L2[Process] --> L3[Output]
    end
    
    subgraph "Conditional Flow (This Episode)"
        C1[Trigger] --> C2{Condition}
        C2 -->|"Met"| C3[Path A]
        C2 -->|"Not met"| C4[Path B]
        C3 --> C5[Rejoin]
        C4 --> C5
    end
    
    style C2 fill:#f59e0b,stroke:#d97706,color:#fff

1. If Node — Binary Splitter

The simplest conditional: one condition, two exits (True / False).

graph TB
    Input[Upstream Items] --> IF{If Node
Condition: price > 100} IF -->|"✅ True"| TrueBranch[Send Coupon] IF -->|"❌ False"| FalseBranch[Log Entry] style IF fill:#f59e0b,stroke:#d97706,color:#fff

Expression Syntax

// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// If Node condition expression types
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

// 📌 Numeric comparison
{{ $json.price > 100 }}              // Greater than
{{ $json.quantity <= 0 }}            // Less than or equal

// 📌 String comparison
{{ $json.status === "active" }}      // Exact match
{{ $json.email.includes("@") }}     // Contains substring
{{ $json.name.startsWith("Dr.") }}  // Starts with

// 📌 Null/empty checks (most common defensive pattern)
{{ $json.data !== null }}            // Not null
{{ $json.items.length > 0 }}         // Array not empty

// 📌 Compound conditions (AND / OR)
{{ $json.age >= 18 && $json.country === "US" }}     // AND
{{ $json.role === "admin" || $json.role === "owner" }}  // OR

// 📌 Regex matching
{{ /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/.test($json.email) }}

2. Switch Node — Multi-Path Router

When you need 3+ branches, Switch is more elegant than nested Ifs.

graph TB
    Input[User Request] --> SW{Switch Node
Field: $json.language} SW -->|"zh"| ZH[Chinese Handler] SW -->|"en"| EN[English Handler] SW -->|"ja"| JA[Japanese Handler] SW -->|"fallback"| DEFAULT[Default: English] style SW fill:#6366f1,stroke:#4f46e5,color:#fff
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// Switch Rules mode configuration
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

// Output 0 (Chinese): {{ $json.language === "zh" }}
// Output 1 (English): {{ $json.language === "en" }}
// Output 2 (Japanese): {{ $json.language === "ja" }}
// Fallback: Items not matching any rule flow here

3. Loop Over Items — Explicit Loops

Some scenarios need explicit control over iteration:

graph TB
    Input[100 Items] --> Loop[Loop Over Items
Batch Size: 10] Loop -->|"Batch 1: Items 0-9"| Process[API Call] Process --> Loop Loop -->|"All done"| Done[Aggregate Results] style Loop fill:#22c55e,stroke:#16a34a,color:#fff
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// Loop Over Items: batch processing with rate limiting
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

// Configuration:
// - Batch Size: 10       // Process 10 Items per loop iteration
// - Add a Wait node (1s pause) inside the loop body to avoid API rate limits

const currentBatch = $input.all();           // Current batch Items (max 10)
const batchIndex = $('Loop Over Items').first().json.$batchIndex;
console.log(`Processing batch ${batchIndex + 1}`);

4. Combined Example: Customer Support Routing

graph TB
    Trigger[📨 Webhook
Receive Support Ticket] --> Validate{If: Content not empty?} Validate -->|"❌ Empty"| Reject[Reply: Please describe your issue] Validate -->|"✅ Has content"| Classify{Switch: Ticket Type} Classify -->|"Refund"| Refund[Refund Approval Flow] Classify -->|"Technical"| Tech[Tech Support Queue] Classify -->|"Complaint"| Complaint[Escalate to Manager] Classify -->|"Other"| General[General Support] Refund --> Priority{If: Amount > $500?} Priority -->|"✅ High"| Manager[Manager Approval] Priority -->|"❌ Low"| Auto[Auto-Refund] style Validate fill:#f59e0b,stroke:#d97706 style Classify fill:#6366f1,stroke:#4f46e5,color:#fff

Next Episode

In Ep 07, we explore n8n 2.0's killer feature — built-in Data Tables — giving your workflows true persistent storage without external database dependencies.