---
title: Liquid filters
description: The filters Quilium registers on top of LiquidJS, their signatures, and the standard LiquidJS filters available alongside them.
updated: 2026-09-20
prev: template-variables
next: partials-helpers
---

Quilium runs on LiquidJS and registers a set of custom filters for i18n, routing, dates, response control, and data shaping. They are the supported way to call the engine helpers; the function-form helpers in the payload are inert in Liquid (see [Variables and context](/en/docs/template-variables)).

## Quilium filters

| Filter | Signature | Behaviour |
|---|---|---|
| `_` / `t` | `'msgid' \| _` | Translate (gettext). `_` is canonical; `t` is an alias with identical behaviour. The msgid is the source string. Only **literal strings** are extractable by `quilium dictionary parse`; a piped variable translates at runtime but is not extracted. Prefer `_`. |
| `url` | `'route' \| url: param: item` or `'route' \| url: {map}` | Resolve a named route to a URL, locale-aware. Substitutes `{{x}}` / `{{x.y}}` tokens from the passed params. See [Routing and URLs](/en/docs/routing-and-urls). |
| `date` | `value \| date: format, modifier` | MomentJS format, default `DD/MM/YYYY`. `modifier` shifts the value (`'+1 days'`, `'next monday'`); a boolean second argument lowercases the meridiem. Locale-aware per request. |
| `redirect` | `url \| redirect: code` | Set `Location` header and status. Default code `301`. |
| `responseCode` | `code \| responseCode` | Set the response status. Default `200`. |
| `setCookie` | `key \| setCookie: value, {options}` | Emit `Set-Cookie`. Options: `maxAge`, `expires`, `path`, `domain`, `secure`, `httpOnly`, `sameSite`. |
| `json` | `value \| json` | `JSON.stringify(value, null, 2)`. |
| `if` | `value \| if: trueVal, falseVal` | Ternary. Returns `trueVal` when truthy, else `falseVal`. |
| `slug` | `str \| slug` | Slugify: strip apostrophes, lowercase, `-` as separator. |
| `regexReplace` | `str \| regexReplace: pattern, replacement, flags, default` | Regex replace. Default flags `s`. |
| `numberFormat` | `value \| numberFormat: decimals, decSep, thouSep` | Format a number. Defaults `2, ',', ' '`. |
| `push` / `unshift` | `array \| push: item` | Immutable append / prepend; returns a new array. Use with `assign` to accumulate. |
| `urlencode` | `value \| urlencode` | `encodeURIComponent`. |
| `markdown` | `text \| markdown` or `text \| markdown: inline: true` | Render Markdown (CommonMark) to HTML, server side. Block output by default (`<p>`, `<ul>`, `<h2>`…); `inline: true` (or `'inline'`) renders inline only, with no wrapping `<p>`, for use inside a heading or a span. Raw HTML in the source is **escaped**, `javascript:` links are refused, bare URLs are auto-linked and a single line break becomes `<br>`. Empty or `null` input returns an empty string. |
| `split` | `str \| split: sep` | Overridden. Default separator `,`. |
| `slice` | `array \| slice: size` | Overridden. Chunks an array into groups (max 200 chunks). ⚠️ **Not the LiquidJS string slice** — on a string it returns **empty**, silently. For a substring use `truncate: n, ''` (first *n* chars). |

## Examples

Translate (literal msgid only):

```liquid
{{ "S'abonner" | _ }}
<span aria-label="{{ 'Navigation principale' | _ }}">
```

Build a locale-aware detail link:

```liquid
<a href="{{ 'article' | url: article: a }}">{{ a.title }}</a>
```

Format a date:

```liquid
{{ a.date | date: 'D MMMM YYYY' }}
{{ now | date: 'YYYY' }}
```

Redirect and set status:

```liquid
{{ '/merci' | redirect: 302 }}
{{ 404 | responseCode }}
```

Ternary and number format:

```liquid
<body class="{{ isDark | if: 'theme-dark', 'theme-light' }}">
{{ price | numberFormat: 2, ',', ' ' }}
```

Render a Markdown field (block, then inline inside a heading):

```liquid
<div class="prose">{{ content.custom.text | markdown }}</div>
<h2>{{ content.custom.title | markdown: inline: true }}</h2>
```

## Engine flags

| Flag | Value | Effect |
|---|---|---|
| `strictFilters` | `true` | An unknown filter is a hard error: the page returns **500**. Typos do not pass silently. |
| `strictVariables` | `false` | An undefined variable renders empty rather than erroring. |
| `cache` | `false` | Templates are not cached; every request re-reads the view. |

## Standard LiquidJS filters

The full LiquidJS filter set is available alongside the Quilium filters. Commonly used: `default`, `append`, `prepend`, `replace`, `strip`, `upcase`, `size`, `contains`, plus the overridden `split` and `slice` above. Standard tags `assign`, `if`, `for`, `case`, `capture` and whitespace control `{%- -%}` work as in stock LiquidJS.

<div class="q-callout q-callout-note"><i class="fa-solid fa-circle-info lead"></i>
  <div><b>Only literal strings are translated at build time.</b> <code>quilium dictionary parse</code> extracts msgids from <code>{{ 'literal' | _ }}</code> only. A piped variable (<code>{{ label | _ }}</code>) still translates at runtime once the msgid exists, but it will not appear in the extracted dictionary, so register such msgids by hand.</div>
</div>
