Skip to content

Kriti Templating Language

Reference for the Kriti JSON templating language used across Nhost to reshape JSON payloads with path lookups, conditionals, loops, and functions.

kriti templating json template transformations path lookup string interpolation

Kriti is a small JSON templating language. It takes a template together with a set of named JSON values and produces a new JSON value. Nhost uses Kriti wherever a feature needs to reshape one JSON document into another, such as request and payload transformations. This page documents the language itself; the variables available inside a template depend on the feature that runs it, and each feature documents its own bindings.

A Kriti template is a superset of JSON: any valid JSON document is also a valid template that renders to itself. To compute a value, wrap an expression in double curly braces:

"http://www.{{ $domain }}.com/{{ $path }}"

The renderer evaluates each {{ ... }} expression against the values bound for the current call and substitutes the result. Everything outside the braces is copied through unchanged.

Expressions reference bound values by name with a leading $. The names that are available, and what they hold, are provided by the feature embedding the template (for instance a transform might bind $body, $base_url, and $session_variables). Referencing a name that was not bound is an error; see Optional lookups to read possibly missing values safely.

{
"id": {{ $body.id }},
"url": "https://example.com/{{ $body.slug }}"
}

Read nested values out of a bound object or array with path syntax:

{{ $body.foo.bar[0]['my key'] }}
SyntaxMeaning
.fieldLook up an object field by name
[n]Look up an array element by integer index (zero-based)
['a b c']Look up an object field whose key is a string literal

Use the bracketed string form for keys that are not valid identifiers, such as keys containing spaces or punctuation. A lookup that fails (an unbound name, a missing field, or an out-of-range index) stops evaluation with an error.

A required lookup fails if any step is missing. To read a value that may not be present, use the optional form. Optional lookups return null instead of failing, and short-circuit: as soon as one step is missing, the whole chain yields null without evaluating the rest.

{{ $body?.foo }}
{{ $body?.foo.bar.baz }}
SyntaxMeaning
name?Optionally look up a variable
?.fieldOptionally look up an object field
?[n]Optionally look up an array index
?['a b c']Optionally look up a string-literal object field

The defaulting operator ?? replaces a null value with a fallback. The expression null ?? true evaluates to true. It pairs naturally with optional lookups to supply a default for a missing value:

{{ $body?.role ?? "user" }}

Expressions support comparison and boolean operators. Parenthesize to control grouping.

OperatorMeaning
==Equal
!=Not equal
< <=Less than, less than or equal
> >=Greater than, greater than or equal
&&Logical AND
||Logical OR
inMembership: x in arr (array element) or "k" in obj (object key)
??Replaces a null left-hand value with the right-hand fallback
{{ if $body.published && ($body.views > 100) }} ... {{ end }}
{{ if "admin" in $session_variables.roles }} ... {{ end }}

Use if / else to choose between values. The branch that matches is rendered in place of the whole block.

{{ if $body.published }}
{
"id": {{ $body.id }},
"title": {{ $body.title }}
}
{{ else }}
null
{{ end }}

Use elif for additional conditions:

{{ if $body.score > 100 }}
"high"
{{ elif $body.score > 50 }}
"medium"
{{ else }}
"low"
{{ end }}

The range keyword iterates over an array, rendering its body once per element and collecting the results into a new array:

{{ range i, x := $body.articles }}
{
"index": {{ i }},
"title": {{ x.title }}
}
{{ end }}

i binds the zero-based index and x binds the element; both names are in scope only inside the loop body. Omit the index by using _ in its place:

{{ range _, x := $body.articles }}
{{ x.title }}
{{ end }}

Ranging over a value that is not an array is an error.

Inside a JSON string, any number of {{ ... }} expressions are evaluated and spliced into the surrounding text. Strings, booleans, and numbers interpolate as their textual form:

"http://www.{{ $domain }}.com/{{ $path }}"

When an expression stands alone as a whole JSON value (not embedded in a string), its result keeps its JSON type. For example, {{ $body.count }} produces a JSON number and {{ $body.tags }} produces a JSON array.

Functions are called with a single argument: functionName(expression). The following functions are always available.

FunctionDescriptionExampleResult
emptytrue for an empty object, array, or (whitespace-only) string, for the number 0, and for null. Errors for a boolean.{{ empty("") }}true
sizeLength of an array or string, number of keys of an object, the value of a number, 1 for true, 0 for false, and 0 for null.{{ size("asdf") }}4
inverseReverses an array or string, returns the reciprocal of a number (errors on 0), negates a boolean, and leaves an object or null unchanged.{{ inverse([1,2,3]) }}[3,2,1]
headFirst element of an array or first character of a string. Errors on an empty value or any other type.{{ head([1,2,3]) }}1
tailDrops the first element of an array or the first character of a string. Errors on an empty value or any other type.{{ tail([1,2,3]) }}[2,3]
toLowerLower-cases a string. Errors for non-strings.{{ toLower("AbCd") }}"abcd"
toUpperUpper-cases a string. Errors for non-strings.{{ toUpper("AbCd") }}"ABCD"
toTitleTitle-cases a string. Errors for non-strings.{{ toTitle("ab cd") }}"Ab Cd"
toCaseFoldNormalizes a string’s casing for case-insensitive comparison. Errors for non-strings.{{ toCaseFold("AbCd") }}"abcd"
escapeUriPercent-encodes a string per RFC 3986, keeping A-Z a-z 0-9 - _ . ~ and encoding everything else. Errors for non-strings.{{ escapeUri("a b/c") }}"a%20b%2Fc"
fromPairsConverts an array of [key, value] pairs into an object. Keys must be strings.{{ fromPairs([["a",1],["b",2]]) }}{"a":1,"b":2}
toPairsConverts an object into an array of [key, value] pairs, in insertion order.{{ toPairs({"a":1,"b":2}) }}[["a",1],["b",2]]
removeNullsRemoves null items from an array (non-recursive).{{ removeNulls([1,null,3]) }}[1,3]
concatConcatenates an array of arrays, of strings, or of objects. For objects, keys from later entries win on collision.{{ concat([[1,2],[3,4]]) }}[1,2,3,4]
notNegates a boolean. Errors for non-booleans.{{ not(true) }}false

When a template cannot be rendered, evaluation stops and reports a typed error with a code and the source span (line and column) where the problem occurred. Common causes are a syntax error, an unbound variable, a type mismatch, or a function applied to an unsupported value. Use optional lookups and the defaulting operator to tolerate missing data rather than failing.

Kriti is the open source templating language created by Hasura (hasura/kriti-lang, Apache-2.0). Nhost implements a compatible engine; this reference describes the behaviour you can rely on across Nhost features.