---
title: "Flexie Scripting: Filters & Working with Lists"
url: https://flexie.io/resources/flexie-scripting/filters-and-collections
description: "Filters reshape a single value. Collection helpers work across a whole list of records. Together they cover most \"format this\" and \"summarise these\" jobs."
---

# Filters & Working with Lists

Last updated 23 May 2026

![A value flowing through chained Flexie Scripting filters, and a list being grouped and totalled](https://flexie.io/image/resources/flexie-scripting-filters-and-collections.png)

## 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 <br>.          | {{ 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](https://flexie.io/resources/flexie-scripting/recipes): these pieces assembled into complete solutions.
* [Where it runs & its limits](https://flexie.io/resources/flexie-scripting/where-it-runs-and-limits): what data is available in each context, and the safety boundaries.
