FEEL Expression Language: A Complete Tutorial for DMN
FEEL — Friendly Enough Expression Language — is the standard expression language defined in the DMN 1.3 specification. Every condition in your decision tables, every output calculation, every hit policy expression is written in FEEL. If you use DMN for business rules — in Camunda, Priostack, or any OMG-compliant engine — you are already using FEEL, even if you did not know the name.
This tutorial covers everything you need to write effective FEEL expressions: the type system, arithmetic, string functions, date handling, list operations, and complete decision table examples you can drop into Priostack today.
What is FEEL?
FEEL was designed with a specific tension in mind: it must be expressive enough for a workflow engine to execute reliably, yet readable enough for a business analyst to write without a developer's help. The "Friendly Enough" in the name acknowledges this compromise.
Key characteristics of FEEL:
- Statically typed — every value has a type: number, string, boolean, date, time, date-time, duration, list, context.
- Null-safe — operations on
nullreturnnullrather than throwing exceptions. - No side effects — expressions cannot modify state; they only compute values.
- Readable range syntax —
[18..65]means "between 18 and 65 inclusive". - Context variables — process variables are available by name, no prefix needed.
Basic Arithmetic
FEEL supports the standard arithmetic operators. Numbers are always arbitrary-precision decimals — there is no integer/float distinction.
| Expression | Result | Notes |
|---|---|---|
| 1 + 2 | 3 | Addition |
| 10 - 3 | 7 | Subtraction |
| 4 * 2.5 | 10 | Multiplication |
| 9 / 4 | 2.25 | Division (exact decimal) |
| 2 ** 8 | 256 | Exponentiation |
| floor(3.7) | 3 | Round down |
| ceiling(3.2) | 4 | Round up |
| decimal(3.14159, 2) | 3.14 | Round to N decimals |
| abs(-5) | 5 | Absolute value |
| modulo(17, 5) | 2 | Remainder |
Comparison and Range Expressions
FEEL's range syntax is one of its most powerful features for decision tables. Instead of writing
age >= 18 and age <= 65, you write:
In decision table input cells you can omit the variable name:
String Functions
FEEL includes a rich set of built-in string functions:
| Expression | Result |
|---|---|
| string length("hello") | 5 |
| upper case("hello") | "HELLO" |
| lower case("WORLD") | "world" |
| substring("BPMN 2.0", 1, 4) | "BPMN" |
| substring after("hello world", "hello ") | "world" |
| string join(["a","b","c"], "-") | "a-b-c" |
| contains("Priostack", "stack") | true |
| starts with("BPMN", "BPM") | true |
| ends with("process.bpmn", ".bpmn") | true |
| matches("abc123", "[a-z]+[0-9]+") | true |
| replace("foo bar", "bar", "baz") | "foo baz" |
| trim(" hello ") | "hello" |
String concatenation uses the + operator:
Date Operations
FEEL has first-class date, time, and duration types. This is critical for business rules involving deadlines, SLAs, and scheduling.
List Operations
FEEL lists are ordered sequences of any type. They are particularly useful for multi-value outputs and for checking membership:
Decision Table Examples
Let us see FEEL in action inside real DMN decision tables. In Priostack, you can deploy DMN tables alongside your BPMN processes and call them from service tasks or gateway conditions.
Example 1: Loan Risk Rating
This decision table assigns a risk category based on credit score and loan amount:
| Credit Score | Loan Amount (€) | Risk Category |
|---|---|---|
| >= 750 | < 50000 | "LOW" |
| [600..749] | [1..30000] | "MEDIUM" |
| [500..599] | - | "HIGH" |
| < 500 | - | "REJECT" |
The output expression for a calculated interest rate could be:
Example 2: Discount Calculation
Example 3: SLA Deadline Check
Integration with Priostack DMN
Priostack evaluates FEEL expressions natively — no external rule engine, no scripting sandbox. Your DMN decision tables deploy as part of your process definition and are called synchronously during process execution. Variables from the process context are automatically available as FEEL context entries.
To evaluate a decision table from a BPMN service task, call the Priostack REST API:
Response:
You can also call decisions inline from within BPMN by adding a business rule task with the decision reference set to your DMN decision key. No extra code needed.
For interactive FEEL expression testing and the full function reference, see the Priostack FEEL documentation.
Start using DMN and FEEL in your workflows today
Deploy your first decision table in minutes with a free Priostack account. No infrastructure required.
FEEL docs Quickstart guideFrequently Asked Questions
What is FEEL in DMN?
FEEL stands for Friendly Enough Expression Language. It is the expression language defined in the DMN 1.3 specification, used to write input conditions and output values in decision tables. FEEL is designed to be readable by business analysts while being precise enough for execution engines.
Is FEEL case-sensitive?
Yes. FEEL is case-sensitive. Variable names, function names, and keywords must match exactly.
true and false are lowercase boolean literals. Built-in functions like
string length use lowercase with spaces.
What is the difference between FEEL and JUEL?
FEEL is the OMG-standard expression language for DMN decision tables. JUEL (Java Unified Expression Language) is a Java-specific EL used in older Camunda 7 versions. Priostack uses FEEL 1.3, which is portable and standards-based.
Can FEEL expressions access process variables?
Yes. When a DMN decision is evaluated from within a BPMN process, process variables are available
as FEEL context variables by name. If your process has a variable customerAge, use it
directly: customerAge >= 18.
How do I test FEEL expressions without deploying a full process?
The Priostack FEEL docs page includes an interactive evaluator. You can
also evaluate expressions via the REST API: POST /api/v1/feel/evaluate with the
expression and context variables as JSON.
Related: ArchiMate layers and enterprise modeling · Two-layer BPMN architecture · Full FEEL language reference