Exclusive Gateway (XOR)
The Exclusive Gateway (also known as XOR Gateway) makes either/or decisions by choosing exactly ONE path from multiple options based on conditions.
Symbolβ
In BPMN diagrams, it's shown as a diamond with an "X" marker or empty diamond.
When to Useβ
Use Exclusive Gateways when you need to:
- Make approve/reject decisions
- Route based on amount thresholds
- Branch based on risk levels (Low/Medium/High)
- Direct to different approval levels
- Any scenario where only ONE path should execute
Visual Exampleβ
Result: Only ONE approval task executes (not both)
Implementation Optionsβ
There are two ways to implement Exclusive Gateways:
Option 1: Gateway-Level Condition (Recommended)β
The gateway itself contains a script that returns which flow to take.
BPMN XML Exampleβ
<bpmn:exclusiveGateway id="Gateway_CheckAmount"
name="Check Loan Amount"
default="Flow_Standard">
<bpmn:incoming>Flow_In</bpmn:incoming>
<bpmn:outgoing>Flow_HighValue</bpmn:outgoing>
<bpmn:outgoing>Flow_Standard</bpmn:outgoing>
<!-- Gateway-level condition -->
<bpmn:extensionElements>
<custom:properties>
<custom:property name="Condition" value="
// Return the flow name or ID to take
if (loanAmount > 100000) {
return 'Flow_HighValue';
} else {
return 'Flow_Standard';
}
" />
</custom:properties>
</bpmn:extensionElements>
</bpmn:exclusiveGateway>
<!-- Define the flows -->
<bpmn:sequenceFlow id="Flow_HighValue"
name="High Value (>$100k)"
sourceRef="Gateway_CheckAmount"
targetRef="Task_SeniorApproval" />
<bpmn:sequenceFlow id="Flow_Standard"
name="Standard Amount"
sourceRef="Gateway_CheckAmount"
targetRef="Task_StandardApproval" />
Fields Referenceβ
| Field | Location | Required | Description | Example |
|---|---|---|---|---|
id | Gateway element | β Yes | Unique gateway identifier | Gateway_CheckAmount |
name | Gateway element | βͺ Optional | Descriptive name for the gateway | "Check Loan Amount" |
default | Gateway element | β Recommended | Flow ID to take if condition fails/no match | Flow_Standard |
Condition | Extension property | β Yes (Option 1) | JavaScript that returns flow name/ID | See example |
incoming | Gateway element | β Yes | Incoming sequence flow ID | Flow_In |
outgoing | Gateway element | β Yes | List of outgoing flow IDs | Multiple <outgoing> tags |
Script Contextβ
Your Condition script has access to:
- All process variables:
loanAmount,customerName,creditScore, etc. - Return value: Must be a string matching a flow
idorname
Example Scripts:
// Simple threshold
return amount > 50000 ? 'Flow_Senior' : 'Flow_Standard';
// Multiple conditions
if (creditScore >= 720) {
return 'Flow_Approved';
} else if (creditScore >= 650) {
return 'Flow_Review';
} else {
return 'Flow_Rejected';
}
// Complex logic
const risk = calculateRiskScore(creditScore, debtToIncome, loanAmount);
if (risk < 30) return 'Flow_LowRisk';
if (risk < 60) return 'Flow_MediumRisk';
return 'Flow_HighRisk';
Execution Flowβ
1. Process reaches gateway
2. Engine executes Condition script
3. Script returns flow name/ID (e.g., 'Flow_HighValue')
4. Engine finds matching flow by id or name
5. Process continues down that flow
6. Other flows are NOT executed
Execution Log Exampleβ
[GATEWAY] Evaluating exclusive gateway: Gateway_CheckAmount (Check Loan Amount)
[GATEWAY] Available paths: 2
[GATEWAY] β Flow_HighValue: 'High Value (>$100k)' β Task_SeniorApproval
[GATEWAY] β Flow_Standard: 'Standard Amount' β Task_StandardApproval (DEFAULT)
[GATEWAY] Executing gateway-level condition script
[GATEWAY] Process variables: loanAmount=150000, creditScore=720
[GATEWAY] β Condition script returned: 'Flow_HighValue'
[GATEWAY] β DECISION: Taking flow 'Flow_HighValue' β Task_SeniorApproval
[GATEWAY] Moving to element: Task_SeniorApproval
Option 2: Flow-Level Conditionsβ
Each outgoing flow has its own condition expression. The first flow whose condition evaluates to true is taken.
BPMN XML Exampleβ
<bpmn:exclusiveGateway id="Gateway_RiskLevel"
name="Risk Assessment"
default="Flow_Rejected">
<bpmn:incoming>Flow_In</bpmn:incoming>
<bpmn:outgoing>Flow_LowRisk</bpmn:outgoing>
<bpmn:outgoing>Flow_MediumRisk</bpmn:outgoing>
<bpmn:outgoing>Flow_HighRisk</bpmn:outgoing>
<bpmn:outgoing>Flow_Rejected</bpmn:outgoing>
</bpmn:exclusiveGateway>
<!-- Flow 1: Low Risk -->
<bpmn:sequenceFlow id="Flow_LowRisk"
name="Low Risk"
sourceRef="Gateway_RiskLevel"
targetRef="Task_AutoApprove">
<bpmn:conditionExpression>
creditScore >= 720 && debtToIncomeRatio < 36
</bpmn:conditionExpression>
</bpmn:sequenceFlow>
<!-- Flow 2: Medium Risk -->
<bpmn:sequenceFlow id="Flow_MediumRisk"
name="Medium Risk"
sourceRef="Gateway_RiskLevel"
targetRef="Task_OfficerReview">
<bpmn:conditionExpression>
creditScore >= 650 && creditScore < 720
</bpmn:conditionExpression>
</bpmn:sequenceFlow>
<!-- Flow 3: High Risk -->
<bpmn:sequenceFlow id="Flow_HighRisk"
name="High Risk"
sourceRef="Gateway_RiskLevel"
targetRef="Task_ManagerReview">
<bpmn:conditionExpression>
creditScore >= 580 && creditScore < 650
</bpmn:conditionExpression>
</bpmn:sequenceFlow>
<!-- Default Flow: No condition (fallback) -->
<bpmn:sequenceFlow id="Flow_Rejected"
name="Rejected"
sourceRef="Gateway_RiskLevel"
targetRef="Task_NotifyRejection" />
Fields Referenceβ
| Field | Location | Required | Description | Example |
|---|---|---|---|---|
conditionExpression | Inside <sequenceFlow> | βͺ Optional | Boolean JavaScript expression | creditScore >= 720 |
default | Gateway element | β Recommended | Flow ID if no conditions match | Flow_Rejected |
Condition Expression Syntaxβ
Flow conditions must return true or false:
// Simple comparison
creditScore >= 720
// Multiple conditions (use XML entities)
creditScore >= 720 && debtToIncomeRatio < 36
// Complex expression
(amount > 50000 && creditScore >= 700) || approvalOverride === true
XML Special Characters:
| Character | XML Entity |
|---|---|
&& | && |
< | < |
> | > |
" | " |
Evaluation Orderβ
- Engine evaluates flows in the order they appear in XML (skips default flow)
- First condition that returns
truewins - If no conditions match, takes the
defaultflow - If no default and no matches β process error
Execution Log Exampleβ
[GATEWAY] Evaluating exclusive gateway: Gateway_RiskLevel (Risk Assessment)
[GATEWAY] Available paths: 4
[GATEWAY] β Flow_LowRisk: 'Low Risk' β Task_AutoApprove
[GATEWAY] β Flow_MediumRisk: 'Medium Risk' β Task_OfficerReview
[GATEWAY] β Flow_HighRisk: 'High Risk' β Task_ManagerReview
[GATEWAY] β Flow_Rejected: 'Rejected' β Task_NotifyRejection (DEFAULT)
[GATEWAY] Evaluating flow conditions...
[GATEWAY] Flow_LowRisk: false (creditScore=680, debtToIncomeRatio=42)
[GATEWAY] Flow_MediumRisk: true
[GATEWAY] β DECISION: Taking flow 'Flow_MediumRisk' β Task_OfficerReview
[GATEWAY] Moving to element: Task_OfficerReview
Use Casesβ
Use Case 1: Amount-Based Approval Routingβ
Scenario: Route loan applications to different approval levels based on amount.
Requirements:
- Loans < $50K β Standard approval
- Loans $50K-$250K β Senior approval
- Loans > $250K β Executive approval
Implementation:
<bpmn:exclusiveGateway id="Gateway_Amount" default="Flow_Standard">
<bpmn:extensionElements>
<custom:properties>
<custom:property name="Condition" value="
if (loanAmount > 250000) return 'Flow_Executive';
if (loanAmount > 50000) return 'Flow_Senior';
return 'Flow_Standard';
" />
</custom:properties>
</bpmn:extensionElements>
<bpmn:outgoing>Flow_Executive</bpmn:outgoing>
<bpmn:outgoing>Flow_Senior</bpmn:outgoing>
<bpmn:outgoing>Flow_Standard</bpmn:outgoing>
</bpmn:exclusiveGateway>
Visual Flow:
Use Case 2: Risk-Based Routingβ
Scenario: Different handling based on calculated risk score.
Requirements:
- Low risk (score < 30) β Auto-approve
- Medium risk (30-60) β Officer review
- High risk (60-80) β Manager review
- Very high risk (>80) β Auto-reject
Implementation:
<bpmn:exclusiveGateway id="Gateway_Risk" default="Flow_Reject">
<bpmn:outgoing>Flow_Auto</bpmn:outgoing>
<bpmn:outgoing>Flow_Officer</bpmn:outgoing>
<bpmn:outgoing>Flow_Manager</bpmn:outgoing>
<bpmn:outgoing>Flow_Reject</bpmn:outgoing>
</bpmn:exclusiveGateway>
<bpmn:sequenceFlow id="Flow_Auto" sourceRef="Gateway_Risk" targetRef="Task_Approve">
<bpmn:conditionExpression>riskScore < 30</bpmn:conditionExpression>
</bpmn:sequenceFlow>
<bpmn:sequenceFlow id="Flow_Officer" sourceRef="Gateway_Risk" targetRef="Task_Officer">
<bpmn:conditionExpression>riskScore >= 30 && riskScore < 60</bpmn:conditionExpression>
</bpmn:sequenceFlow>
<bpmn:sequenceFlow id="Flow_Manager" sourceRef="Gateway_Risk" targetRef="Task_Manager">
<bpmn:conditionExpression>riskScore >= 60 && riskScore <= 80</bpmn:conditionExpression>
</bpmn:sequenceFlow>
Use Case 3: Status-Based Branchingβ
Scenario: Handle different customer account statuses differently.
<bpmn:exclusiveGateway id="Gateway_Status">
<bpmn:extensionElements>
<custom:properties>
<custom:property name="Condition" value="
switch(accountStatus) {
case 'ACTIVE': return 'Flow_Process';
case 'SUSPENDED': return 'Flow_Review';
case 'CLOSED': return 'Flow_Reject';
case 'PENDING': return 'Flow_Verify';
default: return 'Flow_Error';
}
" />
</custom:properties>
</bpmn:extensionElements>
</bpmn:exclusiveGateway>
Execution Diagramβ
βββββββββββββββββββββββββββββββββββββββββββ
β 1. Process reaches Exclusive Gateway β
ββββββββββββββββββ¬βββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββ
β 2. Has gateway-level Condition? β
βββββββ¬βββββββββββββββββββββββββ¬βββββββββββ
β YES β NO
βΌ βΌ
ββββββββββββββββββββ ββββββββββββββββββββββ
β Execute script β β Evaluate each β
β Get flow name/ID β β flow's condition β
βββββββ¬βββββββββββββ ββββββββββ¬ββββββββββββ
β β
ββββββββββ¬ββββββββββββββββ
βΌ
ββββββββββββββββββββββββ
β Find matching flow β
ββββββββββββ¬ββββββββββββ
β
βββββββ΄ββββββ
β Found? β
βββ¬ββββββββ¬ββ
YES β β NO
βΌ βΌ
ββββββββββββ βββββββββββββββ
β Take it β β Take defaultβ
ββββββ¬ββββββ ββββββββ¬βββββββ
β β
ββββββββ¬ββββββββ
βΌ
ββββββββββββββββββββββββββ
β Continue on that path β
ββββββββββββββββββββββββββ
Best Practicesβ
β DO:β
- Always set a
defaultflow to handle unexpected cases - Use descriptive flow names:
"High Value (>$100k)"not"Flow_1" - Keep conditions simple - move complex logic to ScriptTask before gateway
- Return exact flow IDs or names from gateway condition
- Test all branches to ensure each path is reachable
β DON'T:β
- Don't forget the default flow - process will error if no condition matches
- Don't use complex expressions directly in conditions - hard to debug
- Don't mix gateway-level and flow-level conditions - choose one approach
- Don't return flow names that don't exist - process will error
- Don't make multiple paths execute - use Inclusive or Parallel for that
Common Patternsβ
Pattern: Pre-Calculate Decision Valueβ
Instead of complex gateway logic, calculate the decision value beforehand:
<!-- 1. Calculate decision value -->
<bpmn:scriptTask id="Task_Calculate" name="Calculate Route">
<bpmn:extensionElements>
<custom:properties>
<custom:property name="Script" value="
// Complex logic here
const riskScore = calculateRisk(creditScore, income, debt);
const employmentYears = calculateEmployment(startDate);
// Set simple decision variable
if (riskScore < 30 && employmentYears > 2) {
approvalRoute = 'AUTO';
} else if (riskScore < 60) {
approvalRoute = 'OFFICER';
} else {
approvalRoute = 'MANAGER';
}
" />
</custom:properties>
</bpmn:extensionElements>
</bpmn:scriptTask>
<!-- 2. Simple gateway uses calculated value -->
<bpmn:exclusiveGateway id="Gateway_Route">
<bpmn:extensionElements>
<custom:properties>
<custom:property name="Condition" value="
// Simple lookup
return 'Flow_' + approvalRoute;
" />
</custom:properties>
</bpmn:extensionElements>
</bpmn:exclusiveGateway>
Benefits:
- Gateway logic is simple and debuggable
- Complex calculation logic is in one place
- Easy to unit test the calculation separately
Troubleshootingβ
Issue: Gateway takes default flow when it shouldn'tβ
Symptoms: Always goes to default path even when other conditions should match
Possible Causes:
- Condition script error
// β Wrong - typo in variable name
return loanAmmount > 50000 ? 'Flow_High' : 'Flow_Low';
// β
Correct
return loanAmount > 50000 ? 'Flow_High' : 'Flow_Low';
- Flow name mismatch
// β Wrong - returns name that doesn't exist
return 'HighValue'; // But flow is named 'Flow_HighValue'
// β
Correct - match exact flow id or name
return 'Flow_HighValue';
- Flow-level condition syntax error
<!-- β Wrong - missing XML entity -->
<bpmn:conditionExpression>
amount > 50000 && creditScore >= 700
</bpmn:conditionExpression>
<!-- β
Correct - use XML entities -->
<bpmn:conditionExpression>
amount > 50000 && creditScore >= 700
</bpmn:conditionExpression>
Check the logs:
[GATEWAY] β WARNING: Condition returned 'xyz' but no matching flow found
[GATEWAY] Available flow IDs: Flow_HighValue, Flow_Standard
[GATEWAY] Available flow names: 'High Value', 'Standard'
[GATEWAY] β Falling back to default flow: Flow_Standard
Issue: Process throws error at gatewayβ
Symptoms: Process execution fails with error at gateway
Possible Causes:
- No default flow and no condition matches
<!-- β Wrong - no default, condition can fail -->
<bpmn:exclusiveGateway id="Gateway_1">
<bpmn:outgoing>Flow_A</bpmn:outgoing>
<bpmn:outgoing>Flow_B</bpmn:outgoing>
</bpmn:exclusiveGateway>
<!-- β
Correct - always have default -->
<bpmn:exclusiveGateway id="Gateway_1" default="Flow_B">
- Gateway has no outgoing flows
<!-- β Wrong - gateway leads nowhere -->
<bpmn:exclusiveGateway id="Gateway_1">
<bpmn:incoming>Flow_In</bpmn:incoming>
</bpmn:exclusiveGateway>
<!-- β
Correct - at least one outgoing -->
<bpmn:exclusiveGateway id="Gateway_1">
<bpmn:incoming>Flow_In</bpmn:incoming>
<bpmn:outgoing>Flow_Out</bpmn:outgoing>
</bpmn:exclusiveGateway>
Issue: Variable is undefined in conditionβ
Symptoms: Condition fails because variable doesn't exist
Solution: Set variables before gateway:
<!-- Prepare variables first -->
<bpmn:scriptTask id="Task_Prepare">
<bpmn:extensionElements>
<custom:properties>
<custom:property name="Script" value="
loanAmount = loanAmount || 0; // Default value
creditScore = creditScore || 0;
" />
</custom:properties>
</bpmn:extensionElements>
</bpmn:scriptTask>
<bpmn:sequenceFlow sourceRef="Task_Prepare" targetRef="Gateway_Check" />
Summaryβ
Exclusive Gateway (XOR):
- β Chooses exactly ONE path from multiple options
- β Use for either/or decisions, routing, branching
- β Two implementation options: gateway-level condition OR flow-level conditions
- β
Always set a
defaultflow - β Keep conditions simple and testable
Next Steps:
- See Parallel Gateway for executing multiple paths simultaneously
- See Inclusive Gateway for conditional multi-path execution
- Browse Use Cases for more real-world examples
- Check Troubleshooting if you encounter issues