Skip to main content

Expression functions

Functions you can call inside {{ ... }}, in any string-typed activity input.

Where an expression goes

A bare name passes the variable itself. Braces are for everything else — property access, arithmetic, a function call, a pipe:

WriteLine(response) # the variable
WriteLine("{{ response.body }}") # a property
WriteLine("{{ len(orders) }} orders") # a call, inside a sentence
WriteLine("{{ orders | filter(.total > 1000) }}")

If you are reaching for Execute Python Code to filter a list, total a column or reshape some text, one of these is almost certainly shorter — and it runs in the workflow rather than in a Python process the robot has to start.

Which language evaluates it

A workflow declares one, in its expressionLanguage option: expr (the default, and what a workflow that omits the key gets), js, or python.

The five packages below are spelled identically in all three, so strings.ToUpper(name) is the same call whichever you picked.

The builtins are not. filter, map, sum, len and the rest of the Built-in groups on this page are expr-lang's own. In JavaScript you write items.filter(i => i.active); in Python, a comprehension. Everything on those pages assumes expr.

The five packages

PackageFunctionsWhat it is
strings.*38Go's strings package, named as Go names it
math.*30Go's math package
fuzzy.*7Approximate string matching — no native equivalent in any of the three languages
collections.*3Glob matching and first-seen deduplication
path.*6File paths, using the robot's own separator

Two overlaps worth knowing before they bite:

  • min/max are not math.Min/math.Max. The builtins take one array, min([3, 1, 2]). The math pair takes two numbers, math.Min(3, 1).
  • get(m, "k") is not m.k. get returns nothing for a key that is not there; m.k fails the step. Use get for anything optional.

Patterns

Every expression here was evaluated against the engine, against three orders — two open, one failed; two suppliers; totals of 1250, 300 and 8400.

You wantExpressionResult
The rows that matterfilter(orders, .total > 1000)the two over 1000
One field from every rowmap(orders, .reference)["ACME-0042", "ACME-0043", "GLOB-0011"]
Both, read left to rightorders | filter(.total > 1000) | map(.reference)["ACME-0042", "GLOB-0011"]
The distinct valuescollections.Unique(map(orders, .supplier))["ACME", "Globex"]
One row per suppliercollections.DistinctBy(orders, "supplier")the first row of each
A totalsum(map(orders, .total))9950
A total of some of themfilter(orders, .status == "open") | map(.total) | sum()9650
An averagemean(map(orders, .total))3316.6666666666665
How many went wrongcount(orders, .status == "failed")1
One recordfind(orders, .reference == "ACME-0042")that row, or nothing
Its positionfindIndex(orders, .status == "failed")1
BucketsgroupBy(orders, .status)a map of status to rows
In ordersortBy(orders, .total)smallest total first
The biggest fewtake(sortBy(orders, .total), 2)the first two of those
A sentence from a liststrings.Join(map(orders, .reference), ", ")"ACME-0042, ACME-0043, GLOB-0011"
Anything at all?len(orders) > 0true
Did any fail?any(orders, .status == "failed")true
A value that may be absentget(payload, "reference")the value, or nothing
Does this filename match?collections.Fnmatch(fileName, "INV-*.pdf")true
A path that works on any robotpath.Combine(path.GetTempPath(), "export.csv")the temp dir plus the name
The name without the extensionpath.GetFileNameWithoutExtension(fileName)"INV-2026-07"
The closest known supplierfuzzy.BestMatch(supplierName, knownSuppliers)"ACME Trading Limited"
How close it wasfuzzy.Similarity(supplierName, "ACME Trading Limited")0.8

Inside a predicate, .field is the current element's field and # is the element itself — filter(codes, # startsWith "A") where the elements are plain strings rather than rows.

Two results that surprise people

keys and values are unordered. keys({"id": 7, "status": "open", "total": 3}) came back ["id", "total", "status"]. Read a map by key; do not read it by position.

path.* returns the robot's separator. path.Combine("reports", "2026") is reports\2026 on a Windows robot and reports/2026 on Linux. That is the point of the package — but it means a path built here and compared as a string against one written with forward slashes will not match.

Groups

GroupFunctionsWhat it covers
Advanced5Compare, cut, UTF-8 validation
Aggregation5Total, average, median, smallest and largest
Array Operations20Length, filtering, mapping, searching, grouping and ordering
Basic Operations4Absolute value, min/max, modulo
Case Conversion3Upper, lower, title case transforms
Collection Helpers3Glob matching and first-seen deduplication
Constants2Mathematical constants (Pi, E)
Exponential & Logarithmic4Natural/base-10/base-2 logarithms, exponential
File Paths6Split and join file paths using the robot's own separator
Fuzzy Matching7Similarity scoring, approximate matching, fuzzy search and lookup
Hyperbolic3Hyperbolic sine, cosine, tangent
Indexing & Counting8Find positions, count occurrences
Map Operations3Keys, values, and member access that tolerates a missing key
Other3Timestamps, dates and durations
Power & Roots4Exponentiation, square/cube roots, hypotenuse
Replacement & Manipulation4Replace, repeat, clone strings
Rounding4Ceil, floor, round, truncate
Search & Check6Contains, prefix/suffix, case-insensitive equality
Splitting & Joining6Split strings, join arrays, whitespace fields
Trigonometric7Sine, cosine, tangent and inverses (radians)
Trimming6Remove whitespace, prefixes, suffixes, character sets
Type Conversions6Convert between int, float, string and JSON
Validation2NaN and infinity checks