Workflow Studio
Decision Tables
Replace complex nested Condition nodes with a spreadsheet-style table of inputs, conditions, and output values — readable by non-technical stakeholders.
A decision table maps a set of input values to output values based on condition rows. Instead of a chain of 10 Condition nodes, you get a clear table that anyone can read and modify. Access decision tables at /workflows/[id]/decision-tables/[tableId].
Table Structure
A decision table has three sections:
- •Input columns — Fields evaluated on each incoming row (e.g.,
severity,category,source). - •Condition rows — Each row defines conditions on the input columns. A row matches when all its conditions are met.
- •Output columns — Values returned when a row matches (e.g.,
assignedTeam,priority,escalateTo).
Example: Incident Routing Table
| # | IN: severity | IN: category | OUT: assignedTeam | OUT: slaPolicyId | OUT: escalate |
|---|---|---|---|---|---|
| 1 | P1 | any | platform-engineering | sla-p1-critical | true |
| 2 | P2 | security | security-team | sla-p2-security | false |
| 3 | P2 | network | network-ops | sla-p2-standard | false |
| 4 | P2 | any | it-support | sla-p2-standard | false |
| 5 | P3, P4 | any | it-helpdesk | sla-p3-low | false |
| 6 | any | any | it-support | sla-p3-low | false |
Hit Policy
The hit policy controls what happens when multiple rows match the input:
| Policy | Key | Description |
|---|---|---|
| First Match | first | Return the output of the first matching row. Rows are evaluated top to bottom. (Most common) |
| Unique | unique | Exactly one row may match. Throws if zero or multiple rows match. |
| Any | any | Multiple rows may match but all matching rows must have identical output values. |
| Collect (array) | collect | Return outputs from ALL matching rows as an array. |
| Rule Order | rule_order | Return outputs from all matching rows in the order they appear in the table. |
Condition Cell Syntax
| Syntax | Matches |
|---|---|
| "P1" | Exactly "P1" |
| "P1", "P2" | Either "P1" or "P2" |
| any | Any value, including null (always matches) |
| not("P1") | Anything except "P1" |
| > 10 | Numeric: greater than 10 |
| >= 10, <= 50 | Numeric range: 10 to 50 inclusive |
| contains("sql") | String contains the substring |
| starts("INC-") | String starts with prefix |
| null | Value is null or missing |
| not null | Value is present and not null |
Using in a Workflow
Add a Decision Table node to the canvas. In its config, select the table and map input fields from upstream node outputs or trigger data. The node's output is the matched row's output columns.
Decision Table Node Config
{
"type": "DecisionTable",
"tableId": "incident-routing",
"inputs": {
"severity": "{{trigger.record.severity}}",
"category": "{{trigger.record.category}}"
}
}
// Output: { assignedTeam, slaPolicyId, escalate }Keep tables focused on a single decision. If you have routing logic AND priority calculation AND SLA assignment in one table, split it into three smaller tables. Smaller tables are easier to debug and audit.