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.

EntryMatches when
-Any value (always passes)
(blank)Same as -
42Value equals 42
> nGreater than n
< nLess than n
>= nGreater than or equal to n
<= nLess than or equal to n
!= nNot 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
trueBoolean true
falseBoolean false
nullValue 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

OperatorMeaning
=Equality (not ==)
!=Inequality
<, >Less than, greater than
<=, >=Less than or equal, greater than or equal

Boolean operators

OperatorExample
andamount > 0 and status = "active"
ortier = "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

FunctionDescription
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

FunctionDescription
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

FunctionDescription
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

FunctionDescription
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

FunctionDescription
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

FunctionDescription
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

OperatorMeaningExample
+Addition / list append for compatible typesamount + tax
-Subtraction (or unary negation)-amount
*Multiplicationamount * 0.05
/Division (returns null on zero)total / count
**Exponentiationbase ** 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 = null is true when x is missing or has been set to null.
  • null = null is true.
  • null + 1, null * 2, null > 0 — all evaluate to null (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.

SituationResult
Reference to a missing variablenull
Arithmetic involving nullnull
Division by zeronull
Out-of-range list indexnull
Comparison between incompatible typesnull
Syntax error in the expressionParse 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