FEEL Reference

FEEL (Friendly Enough Expression Language) is the standard expression language defined by the OMG for use in DMN and BPMN. Expressions in Priostack - sequence-flow conditions, DMN input expressions and output entries, CMMN sentries - use FEEL.

The engine implements a subset of FEEL, and this page lists what it evaluates. An expression outside that subset has no answer: in a gateway condition the instance goes to INCIDENT, and in a DMN cell the deploy refuses it.

Testing an expression: there is no FEEL evaluator you can call on its own today (the FEEL editor page has no working evaluate route behind it). Test an expression where it will run: in a DMN table cell, evaluated with POST /api/v1/decisions/{decisionId}/evaluate, or in a gateway condition, by starting an instance with sample variables and reading where it went.

Types

TypeExampleNotes
number42, 3.14, -764-bit floating point. All numeric literals are numbers.
string"hello", "world"Double-quoted. Supports Unicode.
booleantrue, falseCase-sensitive lowercase.
datedate("2026-05-01")ISO 8601 date. Use today() for current date.
timetime("14:30:00")ISO 8601 time.
date and timedate and time("2026-05-01T14:30:00")Combined date-time value.
durationduration("P1D"), duration("PT2H30M")ISO 8601 duration. P=period, T=time part.
list[1, 2, 3], ["a", "b"]Ordered collection. One-based indexing.
context{ name: "Alice", age: 30 }Key-value map. Access with dot notation: person.name.
nullnullAbsence of a value. null equals only null; x != null is true only when x has a value; <, <=, >, >= with null are false. In a gateway condition a variable that was never set is an error (incident), so initialise it, to null if need be, before the gateway.

Arithmetic Operators

// Basic arithmetic
1 + 2          // => 3
10 - 3         // => 7
4 * 5          // => 20
10 / 3         // => 3.3333...
// there is no exponent operator: ** is not evaluated

// With variables
amount * 1.2   // apply 20% markup
(price - cost) / cost * 100  // percentage margin

// Duration arithmetic
date("2026-05-01") + duration("P30D")  // => date("2026-05-31")
now() - duration("PT1H")               // one hour ago

Comparison Operators

amount = 100        // equal
amount != 100       // not equal
amount < 100        // less than
amount <= 100       // less than or equal
amount > 100        // greater than
amount >= 100       // greater than or equal

// Range expressions (shorthand for comparisons)
amount in [0..100]  // 0 <= amount <= 100 (inclusive)
amount in ]0..100[  // 0 < amount < 100 (exclusive)
amount in [0..100)  // 0 <= amount < 100 (mixed)

// Membership test
status in ("pending", "review", "approved")  // any of these values

A range opening with (, such as (0..100), and a square-bracket list, such as ["pending", "review"], are not accepted after in today: write an exclusive bound with ] or [ turned outward, and a list of values in parentheses.

Logical Operators

true and false     // => false
true or false      // => true
not(true)          // => false

// Compound conditions
amount > 0 and status = "approved"
(tier = "gold" or tier = "platinum") and amount > 100

String Functions

FunctionExampleResult
string length(s)string length("hello")5
substring(s, start)substring("hello world", 7)"world"
substring(s, start, len)substring("hello world", 1, 5)"hello"
contains(s, match)contains("hello", "ell")true
starts with(s, prefix)starts with("hello", "hel")true
ends with(s, suffix)ends with("hello", "llo")true
matches(s, pattern)matches("hello", "hel+")true
upper case(s)upper case("hello")"HELLO"
lower case(s)lower case("HELLO")"hello"
string(x)string(123)"123"
number(s)number("12")12

Not implemented: trim, string join, split.

Date and Time Functions

FunctionDescription
now()Current date and time
today()Current date (without time)
date(s), time(s), date and time(s), duration(s)Build a value from an ISO 8601 string
years and months duration(from, to)Duration between two dates in years and months
.year .month .day .weekday .hour .minute .secondProperties of a date or date-time; weekday is a number, Monday = 1 to Sunday = 7
.years .months .days .hours .minutes .secondsProperties of a duration

Not implemented: day of week, day of year, month of year, week of year.

// Check if a date is at the weekend (d holds a date such as "2026-10-03")
d.weekday >= 6  // => true on Saturday and Sunday

// Calculate age from birthdate, as a value
years and months duration(date("1990-01-15"), today()).years  // => age in years

// Check if overdue
dueDate < today()  // => true if past due

Compare a property read from a variable, as in d.weekday >= 6. A property read directly off a function call works as a value, but comparing it does not work today: years and months duration(date(birth), today()).years >= 18 answers false, and has no answer in a gateway condition.

List Functions

FunctionExampleResult
count(list)count([1, 2, 3])3
sum(list)sum([1, 2, 3])6
min(list)min([3, 1, 2])1
max(list)max([3, 1, 2])3
list contains(list, item)list contains(["a","b"], "b")true

Not implemented: append, concatenate, insert before, remove, reverse, index of, distinct values, flatten, sort.

Filter and Quantifier Expressions

// Filter: keep items matching a condition
items[price > 100]            // all items where price > 100
items[status = "approved"]    // all approved items

// Some/Every quantifiers
some x in items satisfies x.price > 100    // true if any item has price > 100
every x in items satisfies x.valid = true  // true if all items are valid

// For expression: transform a list variable
for item in items return item.name        // list of names
// iterating over a range (for i in 1..5) is not supported

// Access first element
items[1].name    // name of first item (1-based)
items[-1].name   // name of last item

Context Operations

// Create a context
{ name: "Alice", age: 30, address: { city: "Paris" } }

// Access fields
person.name           // => "Alice"
person.address.city   // => "Paris"

// Not implemented: context merge, context(), get entries, get value

Conditional Expressions

// if/then/else
if amount > 1000 then "high" else "low"

// Combine conditions instead of nesting: an if inside another if is not
// supported. Use a decision table for more than two branches.
if tier = "gold" and amount > 500 then 15 else 0

// Guard against a missing value: customer.email when customer holds a value, null otherwise
if customer != null then customer.email else null

Function Definitions

Not supported: the engine evaluates neither function literals nor functions defined inside a context. Put reusable logic in a decision table, or compute it in a worker.

Numeric Functions

FunctionExampleReturns
abs(n)abs(-5)5
floor(n)floor(3.7)3
ceiling(n)ceiling(3.2)4
min(list)min([1,5,3])1
max(list)max([1,5,3])5
sum(list)sum([1,2,3])6

min, max and sum also take separate arguments: sum(1, 2, 3). Not implemented: round up, round down, decimal, product, mean, median.

Usage in DMN Decision Tables

In decision table input cells, FEEL expressions are used as unary tests against the input column value:

Input cellMatches when input value…
"LOW"equals the string "LOW"
< 600is less than 600
[600..750]is between 600 and 750 (inclusive)
"LOW","MEDIUM"is either "LOW" or "MEDIUM"
not("HIGH")is anything except "HIGH"
(empty)matches any value (wildcard)

Output cells contain FEEL expressions, within the subset above:

// Output: fixed string
"approved"

// Output: conditional based on other variables
if amount > 100000 then "escalate" else "approve"

// Output: computed value
amount * interestRate

Usage in BPMN Gateways

In BPMN sequence flows from exclusive gateways, add a <conditionExpression>:

<sequenceFlow id="to-approve" sourceRef="gw1" targetRef="approve-task">
  <conditionExpression>= riskLevel = "LOW" or (riskLevel = "MEDIUM" and amount &lt; 50000)</conditionExpression>
</sequenceFlow>
Tip: Write &lt; for < inside the XML, as above: a raw < is not XML and the deploy answers 422. The leading = is optional: the engine reads amount > 1000 and =amount > 1000 the same way. Writing it keeps the model compatible with Camunda Modeler.

← Back to Docs · Troubleshooting Guide →