n8n Switch Node: Route Workflow Data to Multiple Branches
If you need more than two paths — IF gives you true/false, but what if you have 4 different actions depending on a status field? That's exactly what the Switch node is built for.
In this guide I'll cover:
- Switch node basics (rules vs expression mode)
- Multi-output routing patterns
- How to handle the "default" / fallthrough case
- Real patterns: order status routing, lead scoring, webhook event dispatch
- Free workflow JSON you can import directly
What the Switch Node Does
The Switch node evaluates each incoming item against a set of rules and routes it to the matching output. Unlike IF (2 outputs), Switch supports up to 25 outputs.
Two modes:
- Rules mode — configure each output with a field + operator + value (no code)
- Expression mode — write a JS expression that returns an output index (0-based)
Basic Setup: Order Status Routing
Scenario: you receive orders with a status field (pending, paid, cancelled, refunded). Route each to a different downstream action.
Switch node config (Rules mode):
| Output | Field | Operator | Value |
|---|---|---|---|
| 0 | {{ $json.status }} |
equals | pending |
| 1 | {{ $json.status }} |
equals | paid |
| 2 | {{ $json.status }} |
equals | cancelled |
| 3 | {{ $json.status }} |
equals | refunded |
Each output connects to a different node (Send Slack alert, Trigger fulfillment, Update CRM, etc.).
The Fallthrough / Default Case
By default if no rule matches, the item is dropped silently. To catch unmatched items:
- Enable "Send data to all matching outputs" — off by default
- Or add a final output rule with a catch-all expression:
{{ true }}
Best practice: always add a fallthrough output that logs or alerts on unexpected values.
Expression Mode: Dynamic Routing
When your routing logic is complex (contains math, multiple fields, lookups), use Expression mode:
// Route by lead score tier
const score = $json.lead_score;
if (score >= 80) return 0; // Hot lead → Sales
if (score >= 50) return 1; // Warm → Nurture sequence
if (score >= 20) return 2; // Cold → Weekly digest
return 3; // Unscored → Manual review
Expression mode returns a 0-based integer (output index). Returning null drops the item.
Pattern: Webhook Event Dispatcher
A common Switch use case is a webhook that receives multiple event types and fans out to specialized handlers:
Webhook → Switch (event type) →
[0] payment.succeeded → Stripe fulfillment flow
[1] payment.failed → Retry / alert flow
[2] customer.created → Onboarding flow
[3] subscription.* → Subscription management flow
[default] → Log unexpected event
This keeps each event handler clean and independently maintainable.
Pattern: A/B Test Traffic Split
Use Expression mode for percentage-based splits:
// 20% A, 80% B split
return Math.random() < 0.2 ? 0 : 1;
Or for a true 4-way split:
const r = Math.random();
if (r < 0.25) return 0;
if (r < 0.50) return 1;
if (r < 0.75) return 2;
return 3;
Free Workflow JSON
Here's importable JSON for a Switch-based webhook event dispatcher:
{
"name": "Switch Node — Webhook Event Dispatcher",
"nodes": [
{
"parameters": {
"httpMethod": "POST",
"path": "events",
"responseMode": "onReceived"
},
"name": "Webhook",
"type": "n8n-nodes-base.webhook",
"typeVersion": 1,
"position": [240, 300]
},
{
"parameters": {
"mode": "rules",
"rules": {
"rules": [
{
"conditions": {
"options": { "caseSensitive": true },
"conditions": [
{ "leftValue": "={{ $json.event }}", "rightValue": "payment.succeeded", "operator": { "type": "string", "operation": "equals" } }
]
},
"renameOutput": true,
"outputKey": "payment_success"
},
{
"conditions": {
"options": { "caseSensitive": true },
"conditions": [
{ "leftValue": "={{ $json.event }}", "rightValue": "payment.failed", "operator": { "type": "string", "operation": "equals" } }
]
},
"renameOutput": true,
"outputKey": "payment_failed"
},
{
"conditions": {
"options": { "caseSensitive": true },
"conditions": [
{ "leftValue": "={{ $json.event }}", "rightValue": "customer.created", "operator": { "type": "string", "operation": "equals" } }
]
},
"renameOutput": true,
"outputKey": "customer_created"
}
]
},
"fallbackOutput": "extra"
},
"name": "Switch",
"type": "n8n-nodes-base.switch",
"typeVersion": 3,
"position": [460, 300]
},
{
"parameters": { "jsCode": "// Handle payment.succeeded
console.log('Payment succeeded:', $json);
return $input.all();" },
"name": "Handle Payment Success",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [680, 180]
},
{
"parameters": { "jsCode": "// Handle payment.failed
console.log('Payment failed:', $json);
return $input.all();" },
"name": "Handle Payment Failed",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [680, 280]
},
{
"parameters": { "jsCode": "// Handle customer.created
console.log('Customer created:', $json);
return $input.all();" },
"name": "Handle Customer Created",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [680, 380]
},
{
"parameters": { "jsCode": "// Fallthrough — unexpected event
console.warn('Unexpected event:', $json.event);
return $input.all();" },
"name": "Log Unknown Event",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [680, 480]
}
],
"connections": {
"Webhook": { "main": [[{ "node": "Switch", "type": "main", "index": 0 }]] },
"Switch": {
"main": [
[{ "node": "Handle Payment Success", "type": "main", "index": 0 }],
[{ "node": "Handle Payment Failed", "type": "main", "index": 0 }],
[{ "node": "Handle Customer Created", "type": "main", "index": 0 }],
[{ "node": "Log Unknown Event", "type": "main", "index": 0 }]
]
}
}
}
Import via Workflows → Import from JSON in your n8n instance.
Switch vs IF: When to Use Which
| Scenario | Use |
|---|---|
| Binary true/false | IF node |
| 3+ discrete values (status, type, tier) | Switch node |
| Complex percentage splits | Switch (Expression mode) |
| Nested conditions across multiple fields | IF nodes chained, or Switch + IF combos |
Common Gotchas
Items silently dropped: If no rule matches and you haven't added a fallthrough, items disappear. Always add a default output in production.
Output index vs output key: In Rules mode, outputs are indexed left-to-right (0, 1, 2…). Renaming an output with outputKey only changes the label — downstream nodes connect by position, not name.
typeVersion matters: Switch node typeVersion 3 uses the new Rules engine. If you're on an older n8n instance, you may have typeVersion 1 with different config structure.
Expression mode returns index, not value: Return 0, 1, 2 — not the branch name. A common mistake is returning "payment.succeeded" (string), which won't route correctly.
Troubleshooting
"All items going to output 0": Check your rule values — string comparison is case-sensitive by default. Enable case-insensitive matching in rule options if needed.
"Node has no output connections": You added a rule output but didn't wire it to a downstream node. n8n will warn but still run — items just drop after that output.
"Expression returned undefined": Your JS expression has a missing return or throws an error. Use the expression editor's preview to test against sample data.
More Free Workflow JSON
This is part of a series on every major n8n node. If you want a complete library of pre-built, documented workflow patterns — including Switch-based routers, error handlers, API integrations, and more — I put them together in one pack:
👉 n8n Workflow Starter Pack ($29) — 20+ ready-to-import workflows covering the most common automation patterns, each with setup instructions and comments.
Built something interesting with the Switch node? Drop your use case in the comments — especially creative multi-branch patterns or edge cases you've hit.
Top comments (1)
What do you use the Switch node for most? Webhook event routing, order status branching, or something else? Drop your use case below.