Filters & Working with Lists
Last updated 23 May 2026

What a filter is
A filter transforms a value using the pipe symbol |. The value on the left is fed into the filter on the right:
{{ "hello world" | upper }} → HELLO WORLD
{{ 1234.5 | number_format(2) }} → 1,234.50
Filters chain left to right, each one receives the result of the one before:
{{ first_name | trim | capitalize }}
Everyday formatting filters
These are the standard filters available in Flexie Scripting:
| Filter | What it does | Example → result |
|---|---|---|
| upper / lower | Change case. | {{ "abc" | upper }} → ABC |
| capitalize | Capitalise the first letter. | {{ "john" | capitalize }} → John |
| title | Capitalise Each Word. | {{ "acme ltd" | title }} → Acme Ltd |
| trim | Remove surrounding spaces. | {{ " x " | trim }} → x |
| default(x) | Use a fallback when empty. | {{ phone | default("N/A") }} |
| number_format(d, dec, sep) | Format a number. | {{ 1234.5 | number_format(2) }} → 1,234.50 |
| round(p) | Round a number. | {{ 3.146 | round(2) }} → 3.15 |
| abs | Absolute value. | {{ -5 | abs }} → 5 |
| length | Count items or characters. | {{ invoices | length }} |
| join(sep) | Join a list into text. | {{ ["a","b"] | join(", ") }} → a, b |
| split(sep) | Split text into a list. | {{ "a,b,c" | split(",") }} |
| replace({from: to}) | Replace substrings. | {{ s | replace({"-": " "}) }} |
| slice(start, len) | Take part of a list or string. | {{ items | slice(0, 5) }} |
| first / last | First or last item. | {{ invoices | first }} |
| reverse | Reverse a list or string. | {{ items | reverse }} |
| sort | Sort a list. | {{ names | sort }} |
| keys | The keys of a map. | {{ row | keys }} |
| merge(other) | Combine two lists or maps. | {{ a | merge(b) }} |
| nl2br | Turn line breaks into HTML . |
{{ note | nl2br }} |
| striptags | Remove HTML tags. | {{ html | striptags }} |
| escape | Make text safe for HTML. | {{ userText | escape }} |
| raw | Output without escaping (use with care). | {{ trustedHtml | raw }} |
| json_encode | Turn data into a JSON string. | {{ row | json_encode }} |
| url_encode | Make text URL-safe. | {{ q | url_encode }} |
| map, filter, reduce, batch | Transform, narrow, fold, or chunk a list. | {{ items | filter(i => i.active) }} |
Flexie's own filters
On top of the standard set, Flexie adds these:
| Filter | What it does | Example |
|---|---|---|
| cast_int | Force a value to a whole number (strips commas). | {{ "1,234" | cast_int }} → 1234 |
| cast_float(precision=0) | Force a value to a decimal number. | {{ "12.5" | cast_float(2) }} |
| cast_string | Force a value to text. | {{ 123 | cast_string }} |
| cast_bool | Force a value to true or false. | {{ "1" | cast_bool }} |
| slugify(sep="-") | Make a URL-safe slug. | {{ "Hello World!" | slugify }} → hello-world |
| json_decode | Parse a JSON string into data. | {{ body | json_decode }} |
| json_path(expr) | Extract a nested value by path. | {{ data | json_path("$.total") }} |
| regex_replace(pattern, replacement, limit=-1) | Pattern-based find and replace. | {{ s | regex_replace("/\\s+/", " ") }} |
| group_by(key) | Group a list of records by a field. | {{ deals | group_by("stage") }} |
| unique_by(key) | Drop duplicates by a field. | {{ contacts | unique_by("email") }} |
| sum_by(key, scale=4) | Total a numeric field across records. | {{ items | sum_by("amount") }} |
| sort_by(key, dir="ASC") | Sort records by a field. | {{ invoices | sort_by("due_date", "DESC") }} |
Working across a list of records
You will often fetch many records (with findMany, getSmartListRecords, findDeals, etc.) and then summarise or reshape them. These helpers do that.
Totals and statistics
| Function | What it does |
|---|---|
| sumField(list, field) | Add up one field across a list. |
| avgField(list, field) | Average one field across a list. |
| minField(list, key) | Smallest value of a field. |
| maxField(list, key) | Largest value of a field. |
| countDistinct(list, field) | How many different values a field has. |
{% set invoices = findMany("invoice", "contact_id", id) %}
Total billed: {{ sumField(invoices, "total_incl_tax") | number_format(2) }}
Largest: {{ maxField(invoices, "total_incl_tax") | number_format(2) }}
Reshaping a list
| Function | What it does |
|---|---|
| collectionColumn(list, column, indexBy=null) | Pull a single column out as a flat list, or, with indexBy, build a lookup map keyed by another column. |
{# A flat list of every email on the account #}
{{ collectionColumn(getAccountContacts(id), "email") | join(", ") }}
Looping with grouping, a worked example
Show invoices grouped by status, with a subtotal per group:
{% set invoices = findMany("invoice", "contact_id", id) %}
{% set grouped = invoices | group_by("status") %}
{% for status, rows in grouped %}
{{ status | upper }} ({{ rows | length }})
{% for inv in rows | sort_by("due_date") %}
- {{ inv.number }}: {{ inv.total_incl_tax | number_format(2) }}
{% endfor %}
Subtotal: {{ rows | sum_by("total_incl_tax") | number_format(2) }}
{% endfor %}
Reusable blocks, snippets
If you keep retyping the same chunk of content (a header, a signature, a styled footer), an administrator can save it as a snippet and you include it by name:
{% snippet "email_header" %}
... your content ...
{% snippet "email_footer" %}
A snippet is itself Flexie Scripting, so it can contain its own logic and tokens and will see the same record data as the template that includes it.
Next steps
- Recipes: these pieces assembled into complete solutions.
- Where it runs & its limits: what data is available in each context, and the safety boundaries.