Skip to content

Search tags, filters, functions and guides.

Language / Expressions

Language

Expressions

Operators, property access, calls, filters and tests.

Expressions appear inside {{ }} and in tags. They look and behave much like JavaScript.

Literals

null  true  false
42  3.14  1_000_000
"double"  'single'  "with #{ interpolation }"
[1, 2, 3]
{ title: "Home", "data-id": 1, (key): value }
  • Hash keys can be names, strings, numbers or any expression in brackets.
  • { title } is short for { title: title }.
  • ... spreads an array or hash into a new one: [...posts, extra] or { ...defaults, size: "lg" }.
  • Trailing commas are allowed.

Operators

OperatorsMeaning
and or notLogic. Always return true or false
== !=Strict equality, like JavaScript's ===. Null and undefined are equal
< > <= >=Compare two numbers, two strings or two dates
+ - * / % **Arithmetic. Numbers only
//Divide and round down
~Join two values as strings
in not inWhether an array or set contains a value, a string contains a substring, or a hash has a key
starts with ends withCompare the start or end of two strings
a..bAn array of whole numbers from a to b, including both
a ? b : cIf a is true, b, otherwise c. Without : c, null
a ?: ba if it is true, otherwise b
a ?? ba unless it is null or missing, otherwise b
page.kiln
{{ "Total: " ~ price * quantity }}
{{ user.role in ["admin", "editor"] ? "Can edit" : "Read only" }}
{{ path starts with "/blog/" }}
{{ user.nickname ?? user.name }}
{{ (1..5)|join(", ") }}
Output
Total: 36
Can edit
true
Ada
1, 2, 3, 4, 5

+ never joins strings, and adding a number to a string is an error. Use ~ to join text. It runs after arithmetic, so "Total: " ~ price * quantity works without brackets.

Reading properties

Use . or [] to read a property. They read the same things, so use whichever fits.

{{ page.title }}
{{ page["title"] }}
{{ page[fieldName] }}
{{ items[0] }}
{{ page?.author?.name }}

?. returns null when the left side is null or missing, and stops there. Method calls work the same way, so post?.summary() is null when there is no post. Nothing after it runs, so keys in brackets and method arguments later in the chain are not evaluated. In strict mode, reading a missing property is an error unless you guard it with ?., ??, default or is defined.

Calling functions

Call a function by name with brackets. Arguments can be positional, named, or both.

{{ range(1, 10, 2)|join(", ") }}
{% set page = document("page", slug: route.path) %}

Named arguments are gathered into one hash at the end. document("page", slug: route.path) passes exactly the same arguments as document("page", { slug: route.path }). Built-in filters and functions also accept their parameter names, such as round(precision: 2).

... spreads an array into positional arguments: max(...prices).

Filters

A filter changes a value. Write it after a |. Filters run left to right, and brackets are optional when there are no arguments.

page.kiln
{{ title|trim|title }}
{{ tags|join(", ", " and ") }}
Output
Kiln Templates
fast, safe and async

Filters bind tighter than a leading minus sign, so -1|abs is -(1|abs). Write (-1)|abs instead. See the filter reference for every built-in filter.

Tests

A test checks a value and returns true or false. Write it after is or is not.

{% if user is defined %}
{% if loop.index is divisible by(3) %}
{% if items is not empty %}

See Tests for every built-in test.

Arrow functions

Filters such as map, filter, sort and reduce take a short function. Write its parameters, then =>, then one expression.

page.kiln
{{ posts|filter(p => p.published)|map(p => p.title)|join(", ") }}
{{ posts|reduce((total, p) => total + p.price, 0) }}
Output
Launch, Update
30

Arrow functions can only be passed to filters and functions. You can't store them with set or print them.