Sequence Flow
Sequence flows connect flow nodes — events, tasks, gateways, and sub-processes — and determine which token paths are taken at execution time.
Attributes
| Attribute | Required | Notes |
|---|---|---|
id | yes | Unique flow identifier |
name | no | Display label |
sourceRef | yes | ID of the source node |
targetRef | yes | ID of the target node |
Conditions
A <conditionExpression> child carries a FEEL expression evaluated when the token leaves a node with multiple outgoing flows. The flow is taken if the expression returns true.
<bpmn:sequenceFlow id="f1" sourceRef="svc1" targetRef="task-success">
<bpmn:conditionExpression xsi:type="bpmn:tFormalExpression">=price > 0</bpmn:conditionExpression>
</bpmn:sequenceFlow>
Condition expressions can sit on flows leaving:
- Exclusive (XOR) gateways — exactly one matching flow is taken, ties resolve in document order.
- Inclusive (OR) gateways — every matching flow is taken in parallel.
- Activities — every matching flow is taken in parallel (uncontrolled fork, BPMN 2.0 §13.2.1).
A flow leaving a node that has only one outgoing flow ignores any condition and is always taken.
Default flows
A node with multiple outgoing flows can declare one of them as the default via the default="<flowId>" attribute. The default flow fires when every other outgoing flow's condition evaluates to false. The engine recognises default on:
- exclusive (XOR) gateways
- inclusive (OR) gateways
- tasks (service / user / script / business-rule / send / receive / manual / generic)
- sub-processes (embedded and ad-hoc)
- call activities
A default flow must not carry a <conditionExpression> of its own — its only job is to be the fallback when nothing else matches.
<!-- XOR gateway with a default -->
<bpmn:exclusiveGateway id="gw1" default="f-fallback">
<bpmn:outgoing>f-vip</bpmn:outgoing>
<bpmn:outgoing>f-fallback</bpmn:outgoing>
</bpmn:exclusiveGateway>
<bpmn:sequenceFlow id="f-vip" sourceRef="gw1" targetRef="task-vip">
<bpmn:conditionExpression>=tier = "vip"</bpmn:conditionExpression>
</bpmn:sequenceFlow>
<bpmn:sequenceFlow id="f-fallback" sourceRef="gw1" targetRef="task-default" />
<!-- Service task with a default — same shape, no extra gateway -->
<bpmn:serviceTask id="route" default="f-default">
<bpmn:extensionElements>
<quantum:taskDefinition type="route-task" />
</bpmn:extensionElements>
<bpmn:outgoing>f-route-vip</bpmn:outgoing>
<bpmn:outgoing>f-default</bpmn:outgoing>
</bpmn:serviceTask>
How outgoing flows are selected
When a token leaves a node with multiple outgoing flows, the engine evaluates them in two passes:
- Non-default flows. Each outgoing flow whose condition evaluates to
trueemits a token. A flow without a<conditionExpression>is treated as always-true. The default flow (if any) is skipped in this pass. - Default fallback. If pass 1 emitted zero tokens and the node declares a default flow, the default emits a token.
Behaviour at a glance:
| Source node kind | Multiple non-default flows match | No non-default flows match | No conditional flows, only an unconditional default |
|---|---|---|---|
| Exclusive gateway (XOR) | Take the first match in document order, rest dropped | Take the default if declared, otherwise raise a routing error | Take the default |
| Inclusive gateway (OR) | Take every match in parallel | Take the default if declared, otherwise raise a routing error | Take the default |
| Activity | Emit a token on every match (uncontrolled fork) | Emit on the default if declared, otherwise the token simply has no successor and the activity's branch terminates | Emit on the default |
| Parallel gateway (AND) | Always emits on every outgoing flow, conditions are ignored (warning at validation time) | n/a | n/a |
Three-way example
Consider a service task with three outgoing flows:
f-cond— condition=x > 0, targettask-positive.f-uncond— no condition, targettask-always.f-default— declared asdefault, targettask-fallback.
<bpmn:serviceTask id="route" default="f-default">
<bpmn:extensionElements>
<quantum:taskDefinition type="route-task" />
</bpmn:extensionElements>
<bpmn:outgoing>f-cond</bpmn:outgoing>
<bpmn:outgoing>f-uncond</bpmn:outgoing>
<bpmn:outgoing>f-default</bpmn:outgoing>
</bpmn:serviceTask>
<bpmn:sequenceFlow id="f-cond" sourceRef="route" targetRef="task-positive">
<bpmn:conditionExpression xsi:type="bpmn:tFormalExpression">=x > 0</bpmn:conditionExpression>
</bpmn:sequenceFlow>
<bpmn:sequenceFlow id="f-uncond" sourceRef="route" targetRef="task-always" />
<bpmn:sequenceFlow id="f-default" sourceRef="route" targetRef="task-fallback" />
Outcomes per x:
x value | f-cond (x > 0) | f-uncond (no condition) | f-default (default) | Result |
|---|---|---|---|---|
5 | true → emits | always-true → emits | skipped | Two parallel tokens: task-positive and task-always |
-1 | false → skipped | always-true → emits | skipped | One token: task-always |
| (impossible) | false | (cannot be false) | would emit | f-default never fires here |
The default flow f-default in this model is dead code: as long as f-uncond has no condition, the non-default pass always emits at least one token, and the fallback pass never runs. The validator does not flag this on activities — the same pattern with a different unconditional sibling (e.g. an event) is intentional in some models — but it is worth catching in review. To make the default reachable, give f-uncond a condition that can be false, or remove it.
Gateway-only nuance: parallel and event-based
- Parallel gateways (AND) ignore conditions on outgoing flows entirely. Every outgoing flow activates. A
<conditionExpression>here is a modeling error and the validator emits a warning. - Event-based gateways route on whichever attached intermediate catch event fires first. Their outgoing flows must not carry conditions (validation error) and must each lead to an
intermediateCatchEvent.
Validation
| Check | Severity |
|---|---|
| Default flow ID isn't one of the source node's outgoing flows | Error |
Default flow carries a conditionExpression | Error |
Non-default outgoing flow on an exclusive gateway has no condition (when default is set) | Warning |
| Outgoing flow on a parallel gateway carries a condition | Warning (the condition is ignored) |
| Outgoing flow on an event-based gateway carries a condition | Error |
| Outgoing flow on an event-based gateway leads to a non-catch-event target | Error |
| Start event has any incoming sequence flow | Error |
| End event has any outgoing sequence flow | Error |
| Intermediate catch event does not have exactly one outgoing sequence flow | Error |
Activity marked isForCompensation="true" has incoming flows | Error |
Examples
<!-- Unconditional flow -->
<bpmn:sequenceFlow id="f1" sourceRef="start" targetRef="task1" />
<!-- Conditional flow off a gateway -->
<bpmn:sequenceFlow id="f2" name="price > 0" sourceRef="gw1" targetRef="task2">
<bpmn:conditionExpression xsi:type="bpmn:tFormalExpression">=price > 0</bpmn:conditionExpression>
</bpmn:sequenceFlow>
<!-- Default flow off a gateway (no condition) -->
<bpmn:sequenceFlow id="f3" name="default" sourceRef="gw1" targetRef="task3" />
<!-- gw1 must declare default="f3" -->
<!-- Conditional + default off a service task -->
<bpmn:serviceTask id="route" default="route-fallback">
<bpmn:extensionElements><quantum:taskDefinition type="route-task"/></bpmn:extensionElements>
<bpmn:outgoing>route-vip</bpmn:outgoing>
<bpmn:outgoing>route-fallback</bpmn:outgoing>
</bpmn:serviceTask>
<bpmn:sequenceFlow id="route-vip" sourceRef="route" targetRef="task-vip">
<bpmn:conditionExpression>=tier = "vip"</bpmn:conditionExpression>
</bpmn:sequenceFlow>
<bpmn:sequenceFlow id="route-fallback" sourceRef="route" targetRef="task-standard" />
FAQ
What's the difference between a sequence flow and a message flow in BPMN?
A sequence flow is the solid arrow that connects flow nodes — events, tasks, gateways, sub-processes — within a single process. It carries tokens at runtime and defines the order of execution. A message flow is a dashed arrow in a collaboration diagram that connects two separate participants and visually represents that one participant sends or receives a message from another. The modeler parses and round-trips message flow elements in collaboration diagrams but the engine does not act on them at runtime — actual message dispatch and delivery happens through message throw events, send tasks, message catch events, receive tasks, and the correlation mechanism. Message flows are descriptive, sequence flows execute.
How does a BPMN sequence flow with a condition expression work?
Add a <bpmn:conditionExpression> child carrying a FEEL expression. When a token leaves a source node with multiple outgoing flows, the engine evaluates each condition against the current scope's variables, and the flow is taken if the expression returns true. Condition expressions are meaningful on flows leaving exclusive gateways (the first matching flow in document order wins), inclusive gateways (every match fires), and activities (every match fires as an uncontrolled fork). They are ignored — with a warning at deployment — on flows leaving parallel gateways, since parallel gateways activate every outgoing flow unconditionally. On a node with only one outgoing flow, conditions are ignored entirely.
What is a default flow in BPMN and when does it fire?
A default flow is the fallback outgoing flow taken when every other outgoing flow's condition evaluates to false. Declare it with default="<flowId>" on the source node. The flow itself must not carry a conditionExpression — it is unconditional by design and the validator rejects a default flow that has one. The engine recognises default on exclusive and inclusive gateways, on every kind of task, on embedded and ad-hoc sub-processes, and on call activities. On a gateway with no match and no default, the engine raises a routing error at runtime, on an activity with no match and no default, the branch terminates with no successor.
Can a BPMN task have multiple outgoing flows with conditions?
Yes. Per BPMN 2.0 §13.2.1, an activity with multiple outgoing flows is an "uncontrolled fork": every outgoing flow whose condition evaluates to true emits a token, and matching multiple conditions fans out into parallel branches. The engine supports this directly, and conditions plus a default flow on a task behave exactly the same as on an inclusive gateway. This lets you route from a task without inserting a separate gateway node — useful for trimming incidental nodes off a diagram. Remember the semantics differ from an exclusive gateway, though: an activity with conditional outgoing flows is OR-style (multiple matches fan out), so if you need XOR semantics you still want an explicit exclusive gateway.
In what order are outgoing flows evaluated at an exclusive gateway?
Document order — the order the outgoing flows appear in the BPMN XML. The first flow whose condition returns true is taken and every remaining flow is skipped. If no condition matches and a default flow is declared, the default fires, if no condition matches and there is no default, the engine raises a routing error at runtime. Inclusive gateways and activities behave differently: they evaluate every condition and emit on every match, so document order has no effect on which flows fire.
What happens to a sequence flow without a condition expression?
It depends on the source. From a node with a single outgoing flow, the flow is always taken regardless of any condition. From a node with multiple outgoing flows, an unconditional flow is treated as always-true on activities and inclusive gateways — it emits a token unconditionally on every visit. On parallel gateways it is the normal case (parallel gateways ignore conditions anyway and emit on every outgoing flow). On exclusive gateways, an unconditional non-default flow wins on every visit because it evaluates as true, any flow declared after it in document order is effectively unreachable, and the validator emits a warning when this combination appears alongside a declared default flow.
Can a default flow be set on a BPMN task, not just on a gateway?
Yes. default="<flowId>" is recognised on every task type — service, user, script, business-rule, send, receive, manual, generic — and on embedded sub-processes, ad-hoc sub-processes, and call activities, as well as on exclusive and inclusive gateways. The semantics are identical: the default flow fires when every other outgoing flow's condition evaluates to false. The default flow itself must not carry a conditionExpression, the validator rejects this in both the modeler and the engine.
Why might my default flow never fire?
If any non-default outgoing flow has no conditionExpression, that flow is treated as always-true and emits a token on every visit. The default fallback only fires when every non-default flow evaluates to false, so an unconditional sibling makes the default unreachable. On exclusive gateways the validator catches this combination (default declared alongside a non-default unconditional sibling) and emits a warning.