Ep 06: Branching & Loops — If, Switch, and Loop Nodes Decoded
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:#fff1. 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:#fffExpression 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:#fffNext 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.