n8n If Node
🔀
Flow Control Node

n8n If Node

Master the n8n If node for conditional workflow routing. Learn conditions, operators, AND/OR logic, expressions, and troubleshooting patterns for decision-making workflows.

Every workflow eventually needs to make a decision. Should this order go to the express shipping queue or standard? Does this lead qualify for the sales team or need more nurturing? Is this API response a success that continues the workflow, or an error that triggers an alert?

The If node is how n8n handles these decisions. It evaluates conditions you define and routes data down different paths based on whether those conditions are true or false. Think of it as a fork in the road where your workflow data takes one path or another depending on its characteristics.

The Conditional Routing Problem

Without conditional logic, workflows would treat every piece of data identically. An order for $50 would follow the same path as an order for $5,000. A valid email would be processed the same as an invalid one. Every API response would trigger the same downstream actions regardless of success or failure.

This creates obvious problems. You need different handling for different scenarios. The If node provides that branching logic without requiring any code.

What the If Node Actually Does

The If node examines data against conditions you specify:

  • Evaluates conditions using operators like equals, contains, greater than, or regex patterns
  • Splits the workflow into two paths: true (condition met) and false (condition not met)
  • Supports multiple conditions combined with AND or OR logic
  • Works with any data type including strings, numbers, booleans, dates, objects, and arrays

Data flows in, the node checks your conditions, and routes items to the appropriate output. Items meeting the conditions go to the “true” output. Items failing the conditions go to the “false” output.

What You’ll Learn

  • When to use the If node versus the Switch node
  • All available condition types and operators
  • How to combine multiple conditions with AND/OR logic
  • Expression-based dynamic conditions for complex scenarios
  • The most common mistakes and exactly how to fix them
  • Real-world examples you can adapt to your workflows

When to Use the If Node

Before configuring conditions, understand when the If node is the right choice versus other options.

ScenarioBest ChoiceWhy
Binary yes/no decision (valid/invalid, success/fail)If nodeTwo outcomes is exactly what If provides
Filter items meeting specific criteriaIf nodeTrue output gets matching items, false gets rest
Route by customer tier (bronze/silver/gold/platinum)Switch nodeFour outcomes needs Switch, not nested Ifs
Check if API response succeededIf nodeSuccess/failure is binary
Route by country (10+ countries)Switch nodeMany outcomes require Switch
Complex multi-step logic with calculationsCode nodeWhen If becomes unwieldy, code is cleaner
Check if field exists before processingIf nodeExists/not exists is binary

Rule of thumb: If you need exactly two paths (true/false, yes/no, success/fail), use the If node. If you need three or more distinct paths, use the Switch node. If you find yourself nesting multiple If nodes, that is a sign you should probably use Switch instead.

Understanding Conditions

Every If node condition has three parts: the left value, an operator, and (usually) a right value. Understanding each component prevents the most common configuration errors.

Condition Anatomy

Left Value    Operator    Right Value
---------     --------    -----------
$json.status    equals     "approved"

Left Value: The data you are checking. Usually an expression referencing input data like {{ $json.status }} or {{ $json.order.total }}.

Operator: How you are comparing the values. Equals, contains, greater than, matches regex, exists, and more.

Right Value: What you are comparing against. Can be a static value like "approved" or 100, or another expression for dynamic comparisons.

Data Types

n8n conditions work with different data types. Selecting the correct type prevents false negatives caused by type mismatches.

TypeUse ForExample Values
StringText comparisons"pending", "[email protected]"
NumberNumeric comparisons100, 49.99, 0
BooleanTrue/false checkstrue, false
DateDate/time comparisonsISO dates, timestamps
ObjectCheck object propertiesJSON objects with key-value pairs
ArrayCheck array contentsLists like ["a", "b", "c"]

Common mistake: Comparing a string "100" against a number 100 with the equals operator. These are different types. Enable “Loose Type Validation” in options if your data has inconsistent types, or explicitly convert types in your expressions.

Available Operators

The operator you choose determines how left and right values are compared.

String Operators:

OperatorTrue WhenExample
equalsExact match"pending" equals "pending"
not equalsNo match"pending" not equals "approved"
containsSubstring found"hello world" contains "world"
not containsSubstring absent"hello world" not contains "foo"
starts withBegins with value"order_123" starts with "order_"
ends withEnds with value"file.pdf" ends with ".pdf"
matches regexPattern matches"ABC123" matches [A-Z]+\d+
not matches regexPattern fails"123" not matches [A-Z]+
is emptyString is ""Empty string check
is not emptyString has contentNon-empty string check

Number Operators:

OperatorTrue WhenExample
equalsSame value100 equals 100
not equalsDifferent value100 not equals 50
greater thanLeft exceeds Right150 greater than 100
less thanLeft below Right50 less than 100
greater than or equalLeft is at least Right100 greater than or equal to 100
less than or equalLeft is at most Right99 less than or equal to 100

Boolean Operators:

OperatorTrue WhenExample
is trueValue is truetrue is true
is falseValue is falsefalse is false
existsValue is definedField present in data
does not existValue undefinedField absent from data

Object/Array Operators:

OperatorTrue When
is emptyObject {} or array [] has no items
is not emptyObject or array has items
existsProperty or array exists
does not existProperty or array is absent

Strict vs Loose Type Validation

By default, n8n uses strict type validation. The string "100" does not equal the number 100. This catches data quality issues but can cause unexpected false results when your data has inconsistent types.

Loose type validation converts values before comparing. The string "100" equals the number 100 because both convert to the same value.

To enable loose validation:

  1. Open your If node
  2. Click Add Option
  3. Select Type Validation
  4. Choose Loose

Use loose validation when data comes from external sources with inconsistent typing. Use strict validation when data integrity matters and you want mismatches to fail explicitly.

Combining Conditions: AND vs OR

Real-world decisions often require checking multiple criteria. The If node lets you combine conditions using AND or OR logic.

AND Logic (All Must Be True)

With AND, every condition must pass for the overall result to be true. If any single condition fails, the item goes to the false output.

Example: Route only high-value orders from VIP customers

Condition 1: $json.order_total > 500
AND
Condition 2: $json.customer_tier equals "vip"

Both conditions must be true. A $600 order from a standard customer fails. A $400 order from a VIP customer also fails. Only $500+ orders from VIP customers pass.

OR Logic (Any Can Be True)

With OR, only one condition needs to pass for the overall result to be true. All conditions must fail for the item to go to the false output.

Example: Flag orders needing review

Condition 1: $json.order_total > 1000
OR
Condition 2: $json.is_first_order equals true
OR
Condition 3: $json.payment_method equals "wire_transfer"

If any of these is true, the order gets flagged. A $50 first order passes. A $1500 repeat order with credit card passes. A $200 repeat order with wire transfer passes.

Configuring Multiple Conditions

  1. Add your first condition normally
  2. Click Add Condition to add more
  3. Set the Combine dropdown to either “AND” or “OR”

The combine setting applies to all conditions in the node. You cannot mix AND and OR in a single If node. For complex logic requiring both, either:

  • Use nested If nodes (one checks AND conditions, next checks OR conditions)
  • Use the Code node for full programming logic

Multiple Conditions Example

Scenario: Only process orders that are:

  • Status is “paid” AND
  • Shipping country is “US” AND
  • Order total is greater than 0

Configuration:

ConditionLeft ValueOperatorRight Value
1{{ $json.status }}equalspaid
2{{ $json.shipping_country }}equalsUS
3{{ $json.total }}greater than0

Combine: AND

All three must be true. A paid US order for $50 passes. A pending US order fails. A paid UK order fails.

Your First If Node

Let’s build a practical example step by step: filtering orders above $100 for priority processing.

Step 1: Add the If Node

  1. Open your n8n workflow
  2. Click + to add a node
  3. Search for “If”
  4. Click to add it to your canvas
  5. Connect it to your data source (webhook, HTTP request, etc.)

Step 2: Configure the Condition

With the If node selected:

  1. Click in the Value 1 field
  2. Type {{ $json.order_total }} (or drag the field from the input panel)
  3. Set the operator dropdown to greater than
  4. Enter 100 in the Value 2 field
  5. Leave the data type as Number

Step 3: Test the Node

  1. If you have pinned data or previous execution data, click Test step
  2. Examine the output panel
  3. You should see results split between True and False outputs

True output: Contains items where order_total is greater than 100

False output: Contains items where order_total is 100 or less

Step 4: Connect Downstream Nodes

The If node has two outputs:

  • True output (top): Connect your priority processing nodes here
  • False output (bottom): Connect your standard processing nodes here

Each path can have completely different downstream workflows. Priority orders might go to express shipping and VIP notification. Standard orders follow the regular fulfillment path.

Understanding the Outputs

When you test or execute the workflow:

  • Items go to exactly one output (never both)
  • Each output maintains the full item data
  • Downstream nodes receive items in the original order
  • Empty outputs are normal when no items match (or all items match)

Expression-Based Conditions

Static conditions work for simple cases. But often you need dynamic comparisons, complex logic, or values calculated from data. Expressions unlock this power.

Using Expressions in Conditions

Both left and right values can be expressions. This enables:

Comparing two fields from the same item:

// Left Value
{{ $json.actual_amount }}

// Operator
equals

// Right Value
{{ $json.expected_amount }}

Comparing against calculated values:

// Left Value
{{ $json.order_total }}

// Operator
greater than

// Right Value
{{ $json.minimum_order * 1.1 }}  // 10% above minimum

Referencing data from other nodes:

// Left Value
{{ $json.customer_id }}

// Operator
equals

// Right Value
{{ $('CRM Lookup').item.json.id }}

For detailed expression syntax and patterns, see our comprehensive n8n expressions guide.

Accessing Previous Node Data

When your condition needs data from a specific previous node (not the immediate input), use the $('Node Name') syntax:

// Data from the immediate previous node
{{ $json.fieldName }}

// Data from a specific named node
{{ $('HTTP Request').item.json.status }}

// First item from a node
{{ $('Webhook').first().json.orderId }}

Common mistake: Using $json.fieldName when the data comes from a different branch. This returns undefined because $json refers to the immediate input, not all previous nodes.

Optional Chaining for Safety

When accessing nested properties that might not exist, use optional chaining to prevent errors:

// Unsafe - errors if customer is undefined
{{ $json.customer.email }}

// Safe - returns undefined instead of erroring
{{ $json.customer?.email }}

// With fallback value
{{ $json.customer?.email ?? "unknown" }}

The ?. operator checks if each level exists before accessing the next. Combined with the nullish coalescing operator (??), you can provide sensible defaults.

Complex Expression Examples

Check if array contains a value:

// Left Value
{{ $json.tags.includes("priority") }}

// Operator
equals

// Right Value (Boolean type)
true

Check string length:

// Left Value
{{ $json.description.length }}

// Operator
greater than

// Right Value
100

Date comparison:

// Left Value
{{ new Date($json.created_at) }}

// Operator
greater than

// Right Value
{{ new Date(Date.now() - 24 * 60 * 60 * 1000) }}  // 24 hours ago

Test complex expressions before running workflows using our expression validator tool.

Common Mistakes and How to Fix Them

After reviewing hundreds of community forum posts and support requests, these are the mistakes that trip up most users. Each includes the exact fix.

Mistake 1: Type Mismatch in Comparisons

Symptom: Condition should match but always goes to false output.

Cause: Comparing different types. String "100" does not equal number 100 in strict mode.

Example:

API returns: amount = "150" (a string, not a number)
Condition: $json.amount greater than 100 (comparing to number)
Result: False (string "150" vs number 100)

Fix: Either:

  • Convert in expression: {{ Number($json.amount) }}
  • Enable loose type validation in node options
  • Fix the data source to return correct types

Mistake 2: Undefined Field References

Symptom: Error message about undefined values, or condition fails unexpectedly.

Cause: Using $json.fieldName when data comes from a different node than the immediate input.

Example:

Webhook triggers workflow → HTTP Request → If node
If condition uses: {{ $json.webhookField }}
Result: Undefined (because $json refers to HTTP Request output)

Fix: Reference the correct node explicitly:

{{ $('Webhook').item.json.webhookField }}

Mistake 3: Both True and False Branches Executing

Symptom: Nodes connected to both If outputs run, even though only one should.

Cause: A Merge node downstream waits for both inputs, triggering execution of both branches even when one has no data.

Why this happens: n8n’s execution model means Merge nodes can pull data through connected paths even when the If node didn’t send data that way.

Fix:

Option 1: Add a Filter node or another If node after the Merge to filter empty results

Option 2: Restructure workflow to avoid Merge after If nodes

Option 3: Use the “Loose” merge mode and handle empty arrays in downstream logic

Mistake 4: Empty vs Null vs Undefined Confusion

Symptom: “is empty” operator doesn’t work as expected.

Cause: These are three different states:

StateWhat It Means”Is Empty” Result”Exists” Result
""Empty stringTrueTrue
nullNull valueFalseTrue
undefinedField doesn’t existFalseFalse
[]Empty arrayTrueTrue
{}Empty objectTrueTrue

Fix: Use the correct operator:

  • Use exists to check if a field is present at all
  • Use is empty to check if a present field has no content
  • Use equals with explicit values for null checks

Mistake 5: Expression Syntax Errors

Symptom: Error about invalid expressions or unexpected tokens.

Common causes:

Missing expression brackets:

Wrong: $json.email
Right: {{ $json.email }}

Trailing period:

Wrong: {{ $json.customer. }}
Right: {{ $json.customer }}

Unclosed brackets:

Wrong: {{ $json.items[0].name }
Right: {{ $json.items[0].name }}

Fix: Use our workflow debugger to identify exactly where the expression fails.

Mistake 6: Case Sensitivity Issues

Symptom: String comparison fails even though values look identical.

Cause: "Pending" does not equal "pending" by default.

Fix: Normalize case in your expression:

// Left Value
{{ $json.status.toLowerCase() }}

// Right Value
pending

Or enable case-insensitive comparison in the options (if available for your operator).

If Node vs Switch Node

Choosing between If and Switch affects workflow readability and maintainability. Here’s when to use each.

Comparison Table

CriteriaIf NodeSwitch Node
Number of outputs2 (true/false)Unlimited
Best forBinary decisionsMultiple distinct routes
Fallback handlingFalse output is fallbackExplicit fallback output
ComplexitySimpler for two pathsSimpler for 3+ paths
ReadabilityClear for yes/noClear for categorization

When to Choose If

Use the If node when:

  • Binary outcomes: Success/failure, valid/invalid, approved/rejected
  • Filtering data: Separating items that match criteria from those that don’t
  • Simple threshold checks: Amount above/below limit, date before/after cutoff
  • Existence checks: Field present/absent, array empty/populated

When to Choose Switch

Use the Switch node when:

  • Multiple categories: Status values (pending/processing/complete/failed)
  • Regional routing: Different paths for US/EU/APAC/other
  • Tier-based logic: Bronze/silver/gold/platinum customer handling
  • Type-based processing: Different actions for order/refund/subscription events

Avoiding Nested If Nodes

A common anti-pattern is nesting multiple If nodes:

If (status = pending)
  └── If (priority = high)
       └── If (amount > 1000)
            └── Process

This becomes hard to follow and maintain. Instead:

Option 1: Use Switch node with combined conditions

Option 2: Use Code node for complex branching logic

Option 3: Rethink the workflow structure to separate concerns

If you find yourself nesting more than two If nodes, that’s a strong signal to refactor.

Real-World Examples

Example 1: Route Orders by Customer Tier

Scenario: VIP customers get priority processing and notifications. Regular customers follow the standard path.

Configuration:

Left Value: {{ $json.customer.tier }}
Operator: equals
Right Value: vip

True branch: Priority queue, VIP email template, expedited shipping False branch: Standard queue, regular email, normal shipping

Example 2: Validate API Response

Scenario: Check if an API request succeeded before processing the response.

Configuration:

Left Value: {{ $json.success }}
Operator: is true

Or for HTTP status codes:

Left Value: {{ $('HTTP Request').item.json.statusCode }}
Operator: equals
Right Value: 200

True branch: Process response data False branch: Log error, send alert, retry logic

Example 3: Filter Valid Email Addresses

Scenario: Only process items with properly formatted email addresses.

Configuration:

Left Value: {{ $json.email }}
Operator: matches regex
Right Value: ^[^\s@]+@[^\s@]+\.[^\s@]+$

True branch: Email is valid format, proceed with processing False branch: Invalid email, log for review or skip

Example 4: Date-Based Routing

Scenario: Handle recent items differently from older ones.

Configuration:

Left Value: {{ new Date($json.created_at) }}
Operator: greater than
Right Value: {{ new Date(Date.now() - 7 * 24 * 60 * 60 * 1000) }}

This checks if the item was created within the last 7 days.

True branch: Recent item, priority handling False branch: Older item, batch processing

Example 5: Check Array Contents

Scenario: Route differently based on whether an order contains specific product categories.

Configuration:

Left Value: {{ $json.items.some(item => item.category === "electronics") }}
Operator: is true

True branch: Contains electronics, apply special handling False branch: No electronics, standard processing

Pro Tips and Best Practices

1. Name Your If Nodes Descriptively

Instead of “If” or “If1”, use names that describe the decision:

  • “Is VIP Customer?”
  • “Order Over $500?”
  • “API Success?”
  • “Valid Email Format?”

This makes workflows self-documenting and debugging much easier.

2. Test with Representative Data

Before connecting to production systems, test your If node with:

  • Values that should pass (verify true output works)
  • Values that should fail (verify false output works)
  • Edge cases (exact threshold values, empty strings, null values)
  • Real data samples covering all scenarios

Pin data from previous tests to iterate on conditions without re-triggering upstream nodes.

3. Handle Edge Cases Explicitly

Don’t assume data will always be present or formatted correctly:

// Instead of assuming field exists:
{{ $json.amount > 100 }}

// Check first:
{{ $json.amount !== undefined && $json.amount > 100 }}

// Or use optional chaining with fallback:
{{ ($json.amount ?? 0) > 100 }}

4. Document Complex Conditions

When a condition isn’t obvious, add a sticky note in n8n explaining:

  • What business rule the condition implements
  • Why this threshold was chosen
  • Edge cases that might need attention

Future you (and your teammates) will thank you.

5. Keep Conditions Focused

Each If node should make one clear decision. If you find yourself adding many conditions with OR logic, consider whether the workflow design could be simpler.

Sometimes it’s cleaner to:

  • Split into multiple If nodes with clear purposes
  • Use a Switch node for categorization
  • Pre-process data to simplify the condition

6. Monitor for Unexpected Paths

In production, track which output path gets used. If you expect 90% true but see 90% false, something is wrong with either:

  • Your condition logic
  • The incoming data quality
  • Your assumptions about the data

Use n8n’s execution log or add logging nodes to track path distribution.

Our workflow development services can help design robust conditional logic for complex business requirements. For strategic guidance on workflow architecture, explore our consulting services.

Frequently Asked Questions

Why does my If node always go to false even when the condition should match?

This is almost always a type mismatch issue. The most common cause is comparing a string to a number. If your API returns "100" (string) and you compare against 100 (number), strict type checking fails. Check the actual data type in your input by examining the previous node’s output. Either convert the type in your expression using Number($json.amount) or String($json.amount), or enable “Loose Type Validation” in the If node options. Also verify you’re referencing the correct field name, as typos cause undefined values that never match.

How do I check if a field exists versus checking if it’s empty?

These are different checks requiring different operators. Use exists to check whether a field is present in the data at all, even if its value is null or empty. Use is empty to check if a present field has no content (empty string, empty array, empty object). A field can exist but be empty (like name: ""), or not exist at all (field missing from object). If you need both checks, combine them: the field exists AND is not empty. For null specifically, compare with equals against a null value or check in a Code node.

Can I use expressions in both condition values, not just the left side?

Yes. Both the left value and right value fields accept expressions. This enables dynamic comparisons like checking if one field equals another ({{ $json.actual }} equals {{ $json.expected }}), or comparing against calculated values ({{ $json.amount }} greater than {{ $json.limit * 1.1 }}). You can also reference data from other nodes in the right value using {{ $('Node Name').item.json.field }}. This makes conditions fully dynamic based on runtime data rather than just static values.

Why are both my true and false branches executing when only one should?

This counterintuitive behavior typically happens when you have a Merge node downstream from your If node. n8n’s execution model means the Merge node waits for input from all connected branches. This can trigger execution of nodes in both paths even when the If node only sent data down one path. To fix this, either restructure your workflow to avoid Merge after If nodes, add a Filter node after the Merge to remove empty results, or use conditional execution settings on downstream nodes. Check the official n8n documentation on splitting for detailed explanation.

When should I use the If node versus the Switch node for conditional logic?

Use the If node when you have a binary decision with exactly two outcomes: true or false, yes or no, success or failure. Examples include checking if an amount exceeds a threshold, if a field matches a value, or if data is valid. Use the Switch node when you have three or more distinct outcomes that need different handling. Examples include routing by status (pending/processing/complete/failed), by region (US/EU/APAC), or by customer tier (bronze/silver/gold). If you find yourself nesting multiple If nodes to handle different cases, that’s a signal to refactor using a Switch node. Switch nodes are also clearer when you need an explicit fallback for unmatched cases. See our n8n workflow best practices guide for more architectural guidance.

Ready to Automate Your Business?

Tell us what you need automated. We'll build it, test it, and deploy it fast.

âś“ 48-72 Hour Turnaround
âś“ Production Ready
âś“ Free Consultation
⚡

Create Your Free Account

Sign up once, use all tools free forever. We require accounts to prevent abuse and keep our tools running for everyone.

or

By signing up, you agree to our Terms of Service and Privacy Policy. No spam, unsubscribe anytime.