Conditional Logic
Create smart branching paths with if/then conditions, 36 operators, and AND/OR logic groups.
Conditional logic is the decision-making layer of Buildorado that turns static forms and linear workflows into intelligent, adaptive experiences. With 36 comparison operators across 7 data types, AND/OR condition groups, and support for nested rules, you can route users down different paths based on their answers, show or hide form fields dynamically, calculate lead scores, direct payments to the right processor, and build complex decision trees -- all without writing a single line of code.
Where Conditional Logic Is Used
Conditional logic appears in two places across Buildorado, each serving a distinct purpose:
Edge Conditions (Workflow Routing)
Edges are the arrows connecting nodes on the workflow canvas. When you add conditions to an edge, that path is only followed if the conditions evaluate to true at runtime. This is how you create branching workflows -- for example, routing enterprise leads to one sales team and SMB leads to another.
Edge conditions are evaluated by the execution engine after a node completes. The engine checks every outgoing edge from the completed node, evaluates each edge's conditions against the current data context, and follows only the edges that match. If no conditioned edges match, the execution stops on that branch (unless you have a default/fallback edge with no conditions).
Field Visibility Rules (Dynamic Forms)
Inside the form builder, you can attach visibility conditions to any field. A field with visibility conditions is hidden by default and only appears when the conditions are met. This keeps your forms short and relevant -- users only see the fields that apply to them.
For example, a "Company Name" field that only appears when "Account Type" is "Business," or a "Dietary Restrictions" textarea that only appears when the "Attending Dinner?" toggle is on.
All 36 Comparison Operators
Buildorado provides exactly 36 comparison operators organized by data type. Each operator is designed for a specific kind of comparison, and the condition UI dynamically updates the available operator list based on the data type you select. The operator names below are the canonical identifiers used internally by the condition engine. Legacy aliases (like equals for eq, or before for isBefore) are accepted for backward compatibility.
Universal Operators (6)
These operators work with any data type -- string, number, boolean, date, array, or object. They always appear in the operator dropdown regardless of the selected type.
| Operator | Label | Requires Value | Description | Example |
|---|---|---|---|---|
eq | Equals | Yes | Exact match. Supports ignoreCase for strings. | country eq "United States" |
ne | Not equals | Yes | Inverse of eq. | status ne "Cancelled" |
exists | Exists | No | Value is not null and not undefined. | referral_code exists |
notExists | Does not exist | No | Value is null or undefined. | optional_field notExists |
empty | Is empty | No | Value is null, undefined, empty string "", empty array [], or empty object {}. | referral_code empty |
notEmpty | Is not empty | No | Inverse of empty -- value has actual content. | coupon_code notEmpty |
String Operators (8)
Use these operators when the data type is set to string. They apply to Text, Textarea, Email, URL, Select, Radio, and other fields that produce string values. All string operators support the ignoreCase toggle in the condition UI.
| Operator | Label | Description | Example |
|---|---|---|---|
contains | Contains | Actual value contains the expected substring. Also works on arrays (checks if array includes the item). | email contains "@company.com" |
notContains | Does not contain | Actual value does not contain the expected substring. | notes notContains "urgent" |
startsWith | Starts with | Actual value begins with the expected string. | phone startsWith "+1" |
doesNotStartWith | Does not start with | Actual value does not begin with the expected string. | url doesNotStartWith "http://" |
endsWith | Ends with | Actual value ends with the expected string. | email endsWith ".edu" |
doesNotEndWith | Does not end with | Actual value does not end with the expected string. | filename doesNotEndWith ".exe" |
matchesRegex | Matches regex | Actual value matches a regular expression pattern. Patterns capped at 500 characters for ReDoS protection. | zip matchesRegex "^\d{5}(-\d{4})?$" |
doesNotMatchRegex | Does not match regex | Actual value does not match the regex pattern. | input doesNotMatchRegex "<script" |
Tip: The contains operator also works on arrays when the data type is "string" -- if the actual value is an array, it checks whether the array includes the expected item using strict equality.
Numeric Operators (4)
Use these operators when the data type is set to number. They apply to Number, Slider, Rating, and any computed numeric values. Both the actual and expected values are safely coerced to numbers; if either value cannot be parsed as a number (e.g., an empty string or non-numeric text), the condition returns false rather than silently defaulting to zero.
| Operator | Label | Description | Example |
|---|---|---|---|
gt | Greater than | Strictly greater. | budget gt 10000 |
gte | Greater than or equal | Greater than or equal to. | score gte 80 |
lt | Less than | Strictly less. | age lt 18 |
lte | Less than or equal | Less than or equal to. | discount lte 50 |
Tip: The universal eq and ne operators also work for numeric equality checks. You do not need a separate numeric equals operator.
Boolean Operators (2)
Use these when the data type is set to boolean. They apply to Toggle fields and Checkbox fields that produce true/false values. These operators handle truthy coercion: isTrue matches true, the string "true", and the number 1. isFalse matches false, the string "false", and the number 0.
| Operator | Label | Description | Example |
|---|---|---|---|
isTrue | Is true | Value is true, "true", or 1. | agree_to_terms isTrue |
isFalse | Is false | Value is false, "false", or 0. | opt_out_marketing isFalse |
Date Operators (4)
Use these when the data type is set to date. They apply to Date, Time, and Date & Time fields. Date values are parsed via the JavaScript Date constructor; invalid dates cause the condition to return false rather than comparing against epoch zero.
| Operator | Label | Description | Example |
|---|---|---|---|
isAfter | Is after | Actual date is later than the expected date. | start_date isAfter "2026-01-01" |
isBefore | Is before | Actual date is earlier than the expected date. | deadline isBefore "2026-12-31" |
isAfterOrEqual | Is after or equal | Actual date is later than or the same as the expected date. | event_date isAfterOrEqual "2026-06-15" |
isBeforeOrEqual | Is before or equal | Actual date is earlier than or the same as the expected date. | registration isBeforeOrEqual "2026-08-31" |
Tip: Use the universal eq operator for exact date matching, and the between operator (see Range below) for date ranges. The empty/notEmpty universal operators work for checking whether a date field has been filled.
Array Operators (7)
Use these when the data type is set to array. They apply to Multi-Select fields, Checkbox groups, and any node output that produces a list of items.
| Operator | Label | Requires Value | Description | Example |
|---|---|---|---|---|
arrayContains | Contains item | Yes | Array includes the expected value. | interests arrayContains "AI" |
arrayNotContains | Does not contain item | Yes | Array does not include the expected value. | allergies arrayNotContains "Peanuts" |
arrayLengthEq | Length equals | Yes | Array length is exactly the expected number. | items arrayLengthEq 5 |
arrayLengthGt | Length greater than | Yes | Array length is greater than the expected number. | attachments arrayLengthGt 0 |
arrayLengthLt | Length less than | Yes | Array length is less than the expected number. | errors arrayLengthLt 3 |
arrayIsEmpty | Is empty array | No | Array exists and has zero items. Differs from empty -- returns false if value is not an array. | preferences arrayIsEmpty |
arrayIsNotEmpty | Is not empty array | No | Array exists and has one or more items. | skills arrayIsNotEmpty |
Tip: The difference between empty and arrayIsEmpty is important. The universal empty operator returns true for null, undefined, empty strings, empty arrays, AND empty objects. The arrayIsEmpty operator only returns true if the value is specifically an array with zero items -- it returns false for null, strings, or objects.
Set Membership Operators (2)
These operators check whether a single value appears in a list of allowed values. Available for string and number data types. The expected value is an array of allowed (or disallowed) values.
| Operator | Label | Description | Example |
|---|---|---|---|
in | Is in list | Actual value appears in the expected list. | state in ["CA", "NY", "TX", "FL"] |
notIn | Is not in list | Actual value does not appear in the expected list. | country notIn ["CN", "RU", "IR"] |
Tip: The in operator is a convenient alternative to writing multiple OR conditions. Instead of creating three separate state eq "CA" OR state eq "NY" OR state eq "TX" rules, use a single state in ["CA", "NY", "TX"] condition.
Range Operator (1)
This operator checks whether a value falls within an inclusive range. Available for number and date data types. The expected value is a two-element array [lower, upper].
| Operator | Label | Description | Example |
|---|---|---|---|
between | Is between | Actual value falls between lower and upper bound (inclusive on both ends). | salary between [50000, 150000] |
Tip: The between operator is inclusive. age between [18, 65] matches 18, 65, and everything in between. For dates, use ISO format: booking_date between ["2026-06-01", "2026-08-31"].
Object Operators (2)
Use these when the data type is set to object. They check the structure of key-value objects like JSON payloads or nested data.
| Operator | Label | Description | Example |
|---|---|---|---|
objectIsEmpty | Is empty object | Value is a non-null, non-array object with zero keys. | metadata objectIsEmpty |
objectIsNotEmpty | Is not empty object | Value is a non-null, non-array object with one or more keys. | webhook_payload objectIsNotEmpty |
Legacy Operator Aliases
For backward compatibility, the condition engine accepts these legacy operator names and resolves them to the canonical operators listed above. You may encounter these names in older workflows:
| Legacy Name | Resolves To | Notes |
|---|---|---|
equals | eq | Common in older ifElse/switch configs |
not_equals | ne | Underscore-separated variant |
not_empty | notEmpty | Underscore-separated variant |
matches | matchesRegex | Shortened alias |
regex | matchesRegex | Shortened alias |
checked | isTrue | From checkbox-style conditions |
not_checked | isFalse | From checkbox-style conditions |
includes | arrayContains | Array membership alias |
excludes | arrayNotContains | Array membership alias |
before | isBefore | Shortened date alias |
after | isAfter | Shortened date alias |
AND/OR Condition Groups
Individual conditions are powerful, but real-world decisions often require combining multiple conditions. Buildorado supports AND/OR logic groups that let you build arbitrarily complex rules.
AND Groups (All Must Be True)
When you combine conditions with AND, every condition in the group must evaluate to true for the overall group to match. Use AND when you need to verify multiple criteria simultaneously.
Example: Qualified Enterprise Lead
company_size gte 200
AND budget gt 50000
AND industry in ["Technology", "Finance", "Healthcare"]All three conditions must be true. A company with 500 employees and a $100K budget in Technology qualifies. A company with 500 employees and a $5K budget does not.
OR Groups (Any Can Be True)
When you combine conditions with OR, at least one condition in the group must evaluate to true for the overall group to match. Use OR when any of several criteria should trigger the same path.
Example: Priority Support Eligibility
plan eq "Enterprise"
OR annual_spend gt 100000
OR is_partner isTrueIf the user is on the Enterprise plan, OR they spend more than $100K annually, OR they are a partner, they qualify for priority support. Only one condition needs to be true.
Combining AND and OR (Nested Groups)
For complex decisions, you can nest AND and OR groups. The outer group connects inner groups, and each inner group has its own logic.
Example: Regional Pricing Rules
Group 1 (AND):
country in ["US", "CA", "MX"]
AND currency eq "USD"
OR
Group 2 (AND):
country in ["GB", "DE", "FR", "IT", "ES"]
AND currency eq "EUR"
OR
Group 3 (AND):
country eq "JP"
AND currency eq "JPY"This set of rules routes the user to the correct pricing page based on their country and currency. Each inner group uses AND (both country and currency must match), while the outer groups are connected with OR (any regional group can match).
Real-World Conditional Logic Examples
Lead Scoring and Routing
A B2B contact form collects company information and routes leads based on a scoring system.
Workflow setup:
- Contact Form (form node) collects: company_size, annual_revenue, industry, job_title, and use_case.
- AI Scoring (AI node) analyzes the submission and assigns a score from 1 to 100.
- Score Router (branch node) with three conditioned edges:
Edge 1: score gte 80
→ Enterprise Sales Team (Slack notification + CRM record + personal email)
Edge 2: score between [40, 79]
→ SMB Sales Team (email sequence + Google Sheet row)
Edge 3: score lt 40
→ Self-Serve (welcome email + documentation link)This ensures that high-value leads get white-glove treatment while smaller leads are still nurtured automatically. See Workflows for more on how to build multi-path automations.
Payment Routing by Plan
A SaaS signup flow charges different amounts based on the selected plan.
Edge to Stripe Checkout (Basic):
plan eq "Basic" AND billing_cycle eq "Monthly"
→ Charge $29/month
Edge to Stripe Checkout (Pro):
plan eq "Pro" AND billing_cycle eq "Monthly"
→ Charge $79/month
Edge to Stripe Checkout (Enterprise):
plan eq "Enterprise"
→ Route to custom quote form (no automated payment)Using edge conditions to route to different Stripe payment nodes lets you dynamically price your product based on user selections.
Geographic Routing
A global support form routes tickets to regional teams based on the user's location.
Edge to US Support:
country in ["US", "CA", "MX"]
→ Assign to Americas queue, notify #support-americas in Slack
Edge to EU Support:
country in ["GB", "DE", "FR", "IT", "ES", "NL", "SE", "PL"]
→ Assign to EMEA queue, notify #support-emea in Slack
Edge to APAC Support:
country in ["JP", "AU", "SG", "IN", "KR"]
→ Assign to APAC queue, notify #support-apac in Slack
Default Edge (no conditions):
→ Assign to General queueThe default edge (an edge with no conditions) acts as a catch-all for countries not explicitly listed in any group.
Plan-Based Feature Access
A settings form in your product shows different configuration fields based on the user's subscription plan.
Field visibility rules:
- Show "Custom Domain" field only when
plan in ["Pro", "Enterprise"] - Show "API Key" field only when
plan in ["Pro", "Enterprise"] - Show "SSO Configuration" field only when
plan eq "Enterprise" - Show "White Label Branding" field only when
plan eq "Enterprise" - Show "Upgrade Prompt" paragraph only when
plan eq "Free"
This creates a single form that adapts its complexity to the user's plan level, rather than maintaining separate forms for each tier.
Setting Up Field Visibility Rules Step by Step
Follow these steps to add conditional visibility to a form field in the form builder:
- Select the target field -- Click on the field you want to show or hide conditionally.
- Open the Visibility tab -- In the field configuration panel on the right, click the Visibility tab (or Conditions tab, depending on your version).
- Add a condition -- Click Add Condition. Select the source field (the field whose value determines visibility), choose an operator, and enter the comparison value.
- Add more conditions (optional) -- Click Add Condition again to add additional rules. Choose AND or OR to connect them.
- Preview -- Use the preview mode to test. Fill in the source field with a value that matches your condition and verify that the target field appears. Change the value to something that does not match and verify the field disappears.
Important: A field with visibility conditions is hidden by default. It only appears when the conditions evaluate to true. This means that if the field is also marked as required, the required validation only applies when the field is visible. Hidden fields are skipped during validation.
Edge Conditions vs. Field Visibility: When to Use Each
Both features use the same condition engine, but they serve different purposes:
| Feature | Purpose | Where It Applies | When It Evaluates |
|---|---|---|---|
| Edge Conditions | Route execution to different nodes in the workflow | On edges between nodes on the workflow canvas | After a node completes, during execution |
| Field Visibility | Show or hide fields within a single form | On individual fields in the form builder | In real time, as the user fills out the form |
Use edge conditions when:
- You want to send the user to a different form step based on their answers.
- You want to trigger different action nodes (send different emails, call different APIs).
- You need to branch the workflow into parallel or alternative paths.
Use field visibility when:
- You want to show or hide a field within the same form step.
- You want the form to adapt dynamically without navigating to a new step.
- You want to keep a single form clean and relevant by hiding irrelevant fields.
In many workflows, you will use both. For example, a registration form might use field visibility to show a "Company Name" field only for business accounts (within the same step), and then use edge conditions to route business accounts to a different Step 2 than individual accounts.
Debugging Conditions: Common Mistakes and Testing Tips
Common Mistakes
-
Case sensitivity. The
eqoperator is case-sensitive by default."Enterprise"does not match"enterprise". If your users might enter values in different cases, toggle Ignore Case on the condition, or usecontainswith ignoreCase, or normalize values in a downstream code node. -
Empty vs. blank. The
emptyoperator checks whether the field has no value, is an empty string, empty array, or empty object. A field with a single space character is technically not empty. If users might enter whitespace, consider usingmatchesRegexwith a pattern like"^\s*$", or use a code node to trim the value first. -
Number-string mismatch. If a field looks like a number but is actually a string (e.g., a text field where the user types "50"), numeric operators like
gtwill safely coerce the value to a number. If the value cannot be parsed as a number, the condition returns false (it does not silently use zero). However, it is best to use a Number field type when you need numeric comparisons. -
Overlapping conditions. If two edges from the same node have conditions that can both be true simultaneously, both paths will execute. This is by design -- Buildorado workflows support parallel execution. If you want only one path to fire, make your conditions mutually exclusive.
-
Missing default edge. If all outgoing edges from a node have conditions and none of them match at runtime, the execution stops at that node. Always add a default edge (an edge with no conditions) as a fallback to handle unexpected values.
-
Referencing hidden fields. If you use a field's value in an edge condition but that field was hidden by a visibility rule and never filled in, the field's value will be empty. Make sure your edge conditions account for this possibility by including an
empty/existscheck or a default path.
Testing Tips
- Use preview mode for every path. Click Preview in the workflow editor and submit test data that triggers each conditional branch. Verify that the correct path is followed for each scenario.
- Test edge cases. What happens when a field is empty? When a number is zero? When a date is today? Edge cases are where conditions most often break.
- Check the execution log. After running a test submission, open the execution log from the submissions dashboard. It shows exactly which conditions were evaluated, which edges were followed, and what data was available at each step.
- Start simple, then add complexity. Build and test one condition at a time. Once each individual condition works, combine them into groups. This incremental approach makes it much easier to isolate problems.
Performance Considerations
Conditional logic evaluation is extremely fast and should not be a concern for most workflows. However, there are a few things to keep in mind for very complex setups:
- Condition evaluation is synchronous. All edge conditions from a given node are evaluated at the same time. Having 10 conditions on 10 edges is not meaningfully slower than having 1 condition on 1 edge.
- Regex patterns are bounded. If you use the
matchesRegexoperator, Buildorado caps pattern length at 500 characters to prevent catastrophic backtracking (ReDoS). Keep your regex patterns simple and avoid nested quantifiers like(a+)+. - Field visibility evaluates on every keystroke. Visibility conditions are re-evaluated in the browser each time a source field's value changes. For forms with dozens of interdependent visibility rules, there may be a slight delay on very old devices. In practice, this is rarely noticeable.
- Deeply nested condition groups. While Buildorado supports arbitrary nesting of AND/OR groups, keeping your nesting depth to 2-3 levels makes conditions easier to read and debug. If you find yourself nesting 4+ levels deep, consider breaking the logic into multiple branch nodes on the workflow canvas.
Frequently Asked Questions
Can I use the output of an AI node in a condition?
Yes. AI nodes produce output variables just like any other node. If your AI node outputs a field like score or sentiment, you can reference it in edge conditions on downstream edges. For example, {{agent_1.sentiment}} eq "positive" would route the workflow based on the AI's analysis.
How do I create an "else" or default path?
Add an edge from the branch node to the default/fallback node and leave its conditions empty. An edge with no conditions is always followed when no other conditioned edge from the same source node matches. This acts as your "else" branch. You can also explicitly negate the conditions of the other edges if you want the default path to be more explicit.
Can I combine edge conditions with field visibility in the same workflow?
Absolutely. Edge conditions and field visibility are independent features that work together naturally. For example, a form step might hide optional fields with visibility rules to keep the form clean, and then the workflow might branch based on the answers using edge conditions on outgoing edges. This is the recommended pattern for building adaptive, multi-path workflows. See the Form Builder guide for details on visibility setup and the Workflows guide for edge configuration.
What happens when multiple conditioned edges match at the same time?
Buildorado follows all matching edges simultaneously. This means if two conditioned edges from the same node both evaluate to true, both downstream paths execute in parallel. This is intentional and useful for scenarios like "send an email AND create a CRM record" from the same node. If you want only one path to fire, make your conditions mutually exclusive (e.g., use score gte 80 on one edge and score lt 80 on another, rather than overlapping ranges).