Portal Community

When to Use

Configuration

FieldRequiredDescription
Expression Required Template expression that resolves to the string value to match against cases. e.g. {{ $json.status }} or {{ $output.classify.category }}. The resolved value is compared as a string against each case key.
Cases Required Dictionary mapping match values (strings) to output port names. Each key is a possible resolved value of Expression; each value is the port name that fires when that key is matched. Port names can be any descriptive string — e.g. "handlePending", "sendTracking".
DefaultPort Optional Port name to fire when no case key matches the resolved expression. Defaults to "default". Always connect this port — unhandled values are a common source of silent data loss in production workflows.
String comparison: Case matching is string-based. The expression result is converted to a string before comparison. 1 (integer) and "1" (string) both match a case key of "1". Case matching is case-sensitive: "Pending" does NOT match a case key of "pending".

Output Ports

PortFires When
<case port name>The resolved expression value matches this case's key. Exactly one case port fires per execution.
default (or custom)No configured case key matches the resolved expression. Always wire this port — it catches new or unexpected values from external systems.

OutputData Fields

Fields available downstream via $output.<nodeKey>:

FieldTypeDescription
SwitchCasestringThe matched case value — the key from the Cases dictionary that was selected. If the default port fires, this contains the raw unmatched expression result.

Sample Configuration

Order status routing

{
  "Expression": "{{ $json.status }}",
  "Cases": {
    "pending":    "handlePending",
    "shipped":    "sendTrackingEmail",
    "cancelled":  "processRefund",
    "delivered":  "requestReview"
  },
  "DefaultPort": "unknownStatus"
}

Webhook event dispatcher

{
  "Expression": "{{ $json.eventType }}",
  "Cases": {
    "order.created":   "onOrderCreated",
    "payment.received": "onPaymentReceived",
    "refund.requested": "onRefundRequested"
  },
  "DefaultPort": "logUnknownEvent"
}

Payment method routing

{
  "Expression": "{{ $json.paymentMethod }}",
  "Cases": {
    "card":          "processCard",
    "bank_transfer": "processBankTransfer",
    "wallet":        "processWallet"
  },
  "DefaultPort": "unsupportedPaymentMethod"
}

Sample Output

Matched Case Port

The input data routes unchanged to whichever case port matches. The _switch metadata indicates which case was matched.

{
  "eventType": "payment.failed",
  "orderId": "ORD-2025-00123",
  "customerId": "cust_007",
  "amount": 4500.00,
  "currency": "USD",
  "failureCode": "card_declined",
  "_switch": {
    "matchedCase": "payment.failed",
    "caseIndex": 2,
    "totalCases": 5
  }
}

Default Port (no case matched)

{
  "eventType": "order.updated",
  "orderId": "ORD-2025-00124",
  "_switch": {
    "matchedCase": null,
    "routedToDefault": true,
    "totalCases": 5
  }
}

Expression Reference

ExpressionReturns
{{ $output.routeByStatus.SwitchCase }}The matched case key string, e.g. "shipped". Available on all downstream branches.

Validation Errors

ErrorCause
VAL_MISSING_EXPRESSIONThe Expression field is empty or whitespace.
VAL_MISSING_CASESThe Cases dictionary is null or contains no entries.

Node Policies and GuardRails

Pattern Examples

Pattern 1 — Order Status Fan-Out

A central order processing workflow receives orders in various states. Switch fans each to its dedicated handler, keeping each handler focused on a single state transition.

WebhookTrigger  (order event received)
  └─► Switch  [key: "routeByStatus"]
        Expression:  {{ $json.orderStatus }}
        Cases:       { "pending": "notifyWarehouse", "shipped": "sendTracking",
                       "cancelled": "initiateRefund", "delivered": "requestReview" }
        DefaultPort: "logUnknown"
        ├─► notifyWarehouse ──► SlackNode  (alert warehouse team)
        ├─► sendTracking    ──► EmailSmtp  (email customer tracking link)
        ├─► initiateRefund  ──► HttpRequest (POST /refunds)
        ├─► requestReview   ──► EmailSmtp  (ask for product review)
        └─► logUnknown      ──► VariableAssignment (capture raw status)
                                  └─► SlackNode (alert engineering)

Pattern 2 — Tier-Based Feature Gate

Gate workflow capabilities by subscription tier, applying different processing rules and quotas to each tier.

FormTrigger  (export request submitted)
  └─► Switch  [key: "routeByTier"]
        Expression:  {{ $var.userTier }}
        Cases:       { "free": "limitedExport", "starter": "standardExport",
                       "professional": "fullExport", "enterprise": "fullExport" }
        DefaultPort: "unknownTier"
        ├─► limitedExport   ──► [export max 100 rows, add watermark]
        ├─► standardExport  ──► [export max 10,000 rows]
        ├─► fullExport      ──► [unlimited export, scheduled delivery]
        └─► unknownTier     ──► StopWorkflow

Pattern 3 — Locale-Specific Document Generation

Generate region-appropriate documents by routing to locale-specific template and tax calculation nodes.

FormTrigger  (invoice generation request)
  └─► Switch  [key: "routeByLocale"]
        Expression:  {{ $json.locale }}
        Cases:       { "en-US": "usInvoice", "en-GB": "gbInvoice",
                       "de-DE": "deInvoice",  "fr-FR": "frInvoice" }
        DefaultPort: "defaultInvoice"
        ├─► usInvoice      ──► [USD, US tax rules, Letter format]
        ├─► gbInvoice      ──► [GBP, UK VAT, A4 format]
        ├─► deInvoice      ──► [EUR, German MwSt, A4 format]
        ├─► frInvoice      ──► [EUR, French TVA, A4 format]
        └─► defaultInvoice ──► [USD, no tax, standard template]