HomeDocs › FEEL Reference

FEEL Expression Language Reference

Last updated: 2026-04-06 · 12 min read · ← Back to Docs

Contents

  1. Overview
  2. Literals and Types
  3. Operators
  4. Conditionals and Logic
  5. String Functions
  6. Numeric Functions
  7. Date & Time Functions
  8. List Functions
  9. Context (Map) Functions
  10. Usage in DMN Decision Tables
  11. Usage in BPMN Gateways

1. Overview

FEEL (Friendly Enough Expression Language) is the expression language defined in the DMN 1.3 specification. Priostack uses FEEL for:

All FEEL expressions start with = in Priostack (e.g., = amount > 50000). Omit the = in DMN input cells where the implicit comparison is used.

2. Literals and Types

TypeExampleNotes
Number42, 3.14, -100IEEE 754 decimal
String"hello"Double quotes only
Booleantrue, falseLowercase
NullnullAbsence of value
Datedate("2026-01-15")ISO 8601
Timetime("14:30:00")Local or zoned
Date-Timedate and time("2026-01-15T14:30:00Z")RFC 3339
Durationduration("P2D"), duration("PT4H30M")ISO 8601 duration
List[1, 2, 3], ["a","b"]Zero-indexed
Context{name: "Alice", age: 30}Like a JSON object
Range[600..750], (0..100)[ = inclusive, ( = exclusive

3. Operators

OperatorSymbolExample
Arithmetic+ - * / **amount * 0.05
Comparison= != < <= > >=score >= 750
Logical ANDanda > 0 and b < 100
Logical ORorrole = "admin" or role = "owner"
Negationnot()not(status = "active")
In listinstatus in ["pending","review"]
In rangeinscore in [600..750]
Instance ofinstance ofx instance of number

4. Conditionals and Logic

// if-then-else
if amount > 50000 then "high-value" else "standard"

// Nested
if riskLevel = "LOW" then "approved"
else if riskLevel = "MEDIUM" and amount < 50000 then "approved"
else "rejected"

// not() for negation
not(verified)   // equivalent to verified = false

5. String Functions

FunctionExampleReturns
string length(str)string length("hello")5
upper case(str)upper case("hello")"HELLO"
lower case(str)lower case("HELLO")"hello"
substring(str,start,len)substring("hello",1,3)"hel"
string join(list,delim)string join(["a","b"],",")"a,b"
contains(str,sub)contains("hello","ell")true
starts with(str,pre)starts with("hello","hel")true
ends with(str,suf)ends with("hello","llo")true
matches(str,pattern)matches("abc123","[a-z]+[0-9]+")true
replace(str,pattern,replacement)replace("a-b","\\-","_")"a_b"

6. Numeric Functions

FunctionExampleReturns
abs(n)abs(-5)5
floor(n)floor(3.7)3
ceiling(n)ceiling(3.2)4
round up(n,scale)round up(3.145, 2)3.15
round down(n,scale)round down(3.149, 2)3.14
min(list)min([1,5,3])1
max(list)max([1,5,3])5
sum(list)sum([1,2,3])6
product(list)product([2,3,4])24
mean(list)mean([1,2,3])2
median(list)median([1,3,5])3

7. Date & Time Functions

// Get today's date
today()                       // date("2026-04-06")

// Get current date-time
now()                         // date and time("2026-04-06T14:30:00Z")

// Arithmetic
date("2026-04-06") + duration("P7D")   // date("2026-04-13")
now() - date and time("2026-04-01T00:00:00Z")  // duration since 1 Apr

// Extract parts
year(date("2026-04-06"))     // 2026
month(date("2026-04-06"))    // 4
day(date("2026-04-06"))      // 6
hour(time("14:30:00"))       // 14
minute(time("14:30:00"))     // 30

// weekday (1=Monday, 7=Sunday)
day of week(date("2026-04-06"))  // 1 (Monday)
Common gotcha: Duration comparison — duration("P2D") < duration("P3D") works, but mixing day-duration and time-duration (e.g., duration("P1D") + duration("PT2H")) returns a mixed duration. Use duration("P1DT2H") directly.

8. List Functions

FunctionExampleReturns
count(list)count([1,2,3])3
append(list,item)append([1,2],3)[1,2,3]
concatenate(list...)concatenate([1],[2,3])[1,2,3]
insert before(list,pos,item)insert before([1,3],2,2)[1,2,3]
remove(list,pos)remove([1,2,3],2)[1,3]
reverse(list)reverse([1,2,3])[3,2,1]
index of(list,match)index of([1,2,1],1)[1,3]
union(list...)union([1,2],[2,3])[1,2,3]
distinct values(list)distinct values([1,2,1])[1,2]
flatten(list)flatten([[1,2],[3]])[1,2,3]
sort(list, fn)sort([3,1,2], function(a,b) a < b)[1,2,3]
any(list)any([false,true,false])true
all(list)all([true,true])true

9. Context (Map) Functions

// Access context property
{name: "Alice", age: 30}.name     // "Alice"

// get value
get value({name: "Alice"}, "name")  // "Alice"

// get entries
get entries({a: 1, b: 2})  // [{key:"a",value:1},{key:"b",value:2}]

// context merge
context merge({a:1},{b:2})  // {a:1, b:2}

10. 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 full FEEL expressions:

// Output: fixed string
"approved"

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

// Output: computed value
amount * interestRate

11. 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 < 50000)</conditionExpression>
</sequenceFlow>
Tip: Always prefix BPMN conditions with = to tell the engine this is a FEEL expression. Without it, the engine treats it as a literal string comparison.

← Back to Docs · Troubleshooting Guide →