FEEL Reference
FEEL (Friendly Enough Expression Language) is the expression language used in Conduit for gateway conditions, script tasks, decision table input entries, and decision table output entries.
Inside Script Tasks, FEEL is one of three step types — alongside
jq(for JSON reshape) and Rhai (for general scripting). See Script Task for the pipeline model. Gateway conditions and DMN remain FEEL-only.
Input Entry Syntax (Unary Tests)
Input cells in decision tables use unary tests — each cell is tested against the column’s input value. Only a subset of FEEL is allowed here.
| Entry | Matches when |
|---|---|
- | Any value (always passes) |
| (blank) | Same as - |
42 | Value equals 42 |
> n | Greater than n |
< n | Less than n |
>= n | Greater than or equal to n |
<= n | Less than or equal to n |
!= n | Not equal to n |
[a..b] | Inclusive range: a ≤ x ≤ b |
(a..b) | Exclusive range: a < x < b |
[a..b) | Half-open: a ≤ x < b |
(a..b] | Half-open: a < x ≤ b |
"string" | String equals “string” (exact) |
"x","y" | Value is any of x or y (OR) |
not("x","y") | Value is neither x nor y |
true | Boolean true |
false | Boolean false |
null | Value is null |
date("2024-01-01") | Date literal |
Operator Reference (Gateway Conditions & Script Tasks)
Full FEEL is available in gateway conditions, script tasks, and output entries.
Comparison operators
| Operator | Meaning |
|---|---|
= | Equality (not ==) |
!= | Inequality |
<, > | Less than, greater than |
<=, >= | Less than or equal, greater than or equal |
Boolean operators
| Operator | Example |
|---|---|
and | amount > 0 and status = "active" |
or | tier = "gold" or tier = "platinum" |
not(expr) | not(status = "closed") |
Context literals (Script Task output)
{ fee: amount * 0.05, tier: if amount > 1000 then "premium" else "standard" }
Each key is written as a separate process variable.
Conditionals
if amount > 1000 then "premium" else "standard"
Built-in Functions
Numeric
| Function | Description |
|---|---|
abs(n) | Absolute value |
floor(n) | Round down to nearest integer |
ceiling(n) | Round up to nearest integer |
decimal(n, scale) | Round n to scale decimal places |
modulo(n, d) | Remainder of n ÷ d |
sqrt(n) | Square root |
String
| Function | Description |
|---|---|
string length(s) | Length of string |
upper case(s) | Convert to uppercase |
lower case(s) | Convert to lowercase |
substring(s, start) | Substring from position (1-based) |
substring(s, start, len) | Substring with length |
contains(s, sub) | True if s contains sub |
starts with(s, pre) | True if s starts with pre |
ends with(s, suf) | True if s ends with suf |
matches(s, pattern) | True if s matches regex pattern |
replace(s, pattern, rep) | Replace regex matches |
string join(list) | Join list elements into a string |
string join(list, sep) | Join with separator |
List
| Function | Description |
|---|---|
count(list) | Number of elements |
min(list) | Minimum value |
max(list) | Maximum value |
sum(list) | Sum of all values |
mean(list) | Arithmetic mean |
list contains(list, item) | True if list contains item |
append(list, item) | New list with item appended |
flatten(list) | Flatten nested lists one level |
distinct values(list) | Remove duplicates |
reverse(list) | Reversed list |
sort(list, fn) | Sort with comparator function |
sublist(list, start) | Sublist from position |
sublist(list, start, len) | Sublist with length |
union(list1, list2) | Merge two lists, deduplicated |
Date and Time
| Function | Description |
|---|---|
now() | Current date and time |
today() | Current date |
date("2024-01-01") | Parse date literal |
time("12:00:00") | Parse time literal |
date and time("2024-01-01T12:00:00Z") | Parse datetime literal |
duration("P1D") | Parse ISO 8601 duration |
Context
| Function | Description |
|---|---|
get value(context, key) | Get a value from a context by key |
get entries(context) | Get list of { key, value } pairs |
context(entries) | Build a context from a list of key-value pairs |
Conversion
| Function | Description |
|---|---|
string(value) | Convert to string |
number(s) | Parse string to number |
not(bool) | Negate a boolean |
Examples
-- Gateway condition: route high-value orders
amount > 1000 and tier = "gold"
-- Script task: enrich order
{ fee: amount * 0.05, tier: if amount > 1000 then "premium" else "standard", itemCount: count(items) }
-- Decision table output: compute label
if score >= 90 then "excellent" else if score >= 70 then "good" else "needs improvement"
-- String manipulation
upper case(substring(customerId, 1, 3))
-- Date comparison
date(orderDate) < today()
Arithmetic operators
| Operator | Meaning | Example |
|---|---|---|
+ | Addition / list append for compatible types | amount + tax |
- | Subtraction (or unary negation) | -amount |
* | Multiplication | amount * 0.05 |
/ | Division (returns null on zero) | total / count |
** | Exponentiation | base ** 2 |
Mixed integer/decimal arithmetic widens to decimal. null propagates through every arithmetic operator: null + 1 evaluates to null rather than raising.
Property access
Dot notation walks a JSON object. Any segment that is null short-circuits the path to null.
customer.tier
customer.address.country
order.items[1].sku
For nested objects whose existence is uncertain, gate the parent explicitly:
if customer = null then null else customer.tier
List indexing
Lists use 1-based indexing. list[1] is the first element; negative indices are not supported by the evaluator.
items[1] -- first item
items[count(items)] -- last item
items[count(items) - 1] -- second-to-last
Out-of-range indices return null rather than raising.
Null handling
There is no ?? operator. Default a possibly-missing variable with an explicit conditional:
if x = null then 0 else x
Comparisons behave consistently:
x = nullistruewhenxis missing or has been set tonull.null = nullistrue.null + 1,null * 2,null > 0— all evaluate tonull(propagation, not error).- An undefined identifier resolves to
null. Set a default before doing arithmetic if you need a real number.
For a longer set of patterns (counters, accumulators, list building) see the Expressions Cookbook.
Operator precedence
From highest (binds tightest) to lowest:
. property access
[ ] list index
unary - negation
** exponent
* / % multiplicative
+ - additive
< <= > >= = != comparison
not(...) logical not (a function call, not an operator)
and logical and
or logical or
if then else conditional
Use parentheses freely. They cost nothing and remove ambiguity.
Error behaviour
FEEL is forgiving by design: it returns null for situations that other languages would treat as errors.
| Situation | Result |
|---|---|
| Reference to a missing variable | null |
Arithmetic involving null | null |
| Division by zero | null |
| Out-of-range list index | null |
| Comparison between incompatible types | null |
| Syntax error in the expression | Parse error → engine marks the instance error, records a script evaluation failed event |
For gateway conditions, a null result is treated as false — meaning the flow is not taken. If no flow matches and no default flow is configured, the engine raises an error. See Exclusive Gateway.
See also
- Expressions Cookbook — counters, accumulators, null-safe patterns
- Variables & Scopes — how FEEL sees process variables
- Script Task — script-task return shape and Result Variable