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.
- Explicit about null -
nullequals onlynull;x != nullis true only whenxhas a value;<,<=,>,>=withnullare false. In a gateway condition a variable that was never set is an error (the instance goes to incident), so initialise it before the gateway. - 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. There is one number type: no integer/float
distinction. The table lists what the Priostack engine evaluates; it has no exponent operator
(**) and no decimal() or modulo() function.
| Expression | Result | Notes |
|---|---|---|
| 1 + 2 | 3 | Addition |
| 10 - 3 | 7 | Subtraction |
| 4 * 2.5 | 10 | Multiplication |
| 9 / 4 | 2.25 | Division |
| floor(3.7) | 3 | Round down |
| ceiling(3.2) | 4 | Round up |
| abs(-5) | 5 | Absolute value |
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
The Priostack engine evaluates these built-in string functions (substring after,
string join, replace and trim are not implemented):
| Expression | Result |
|---|---|
| string length("hello") | 5 |
| upper case("hello") | "HELLO" |
| lower case("WORLD") | "world" |
| substring("BPMN 2.0", 1, 4) | "BPMN" |
| contains("Priostack", "stack") | true |
| starts with("BPMN", "BPM") | true |
| ends with("process.bpmn", ".bpmn") | true |
| matches("abc123", "[a-z]+[0-9]+") | true |
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 deploy a DMN table with
POST /api/v1/models and call it from a business rule task or through the REST API.
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.
A DMN decision table deploys on its own, through POST /api/v1/models (1 credit; the kind is
detected from the XML), and is then called synchronously during process execution. Variables from the
process context are automatically available as FEEL context entries.
To evaluate a deployed decision directly, call the Priostack REST API. The decision id is in the path, and the body is a flat object of inputs (each evaluation costs 1 credit):
Response:
Output values come back as strings, and an unknown decision answers 422.
You can also call a deployed decision inline from BPMN with a business rule task carrying
<zeebe:calledDecision decisionId="loanRiskRating"/>. The decision's outputs are written
into the process under their own names (here riskCategory). 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?
There is no standalone FEEL evaluation endpoint. Deploy a small decision table with
POST /api/v1/models and evaluate it with POST /api/v1/decisions/{decisionId}/evaluate
(1 credit per call), or try the expression as a gateway condition in a short process. The
FEEL reference lists what the engine evaluates.
Related: ArchiMate layers and enterprise modeling · Two-layer BPMN architecture · Full FEEL language reference