Skip to content


Template Engine Tags

Tags are a set of various built-in constructs and operations over a template. They are declared using code islands and defines the behavior of the template.


Command constructs allows one to run specific commands against template. An important aspect common to all commands is that they never produce content, they only produce side effects.


The set command allows to specify an assignment operation inside a template, it will assign to the result of an expression to the specified variable:

{% set five = 2 + 3 %}

In previous example we assigned the result of evaluating the expression 2 + 3 to the variable five.

Variable name is an identifier and can only contain alphanumeric (latin) characters and underscores, but cannot start with digits.

Note again that the output of previous example will be empty because, as mentioned before, set as a command, does not produce content, it just affects the context defining, or redefining a variable.


The global command is the same as set but it will assign the result of evaluating the expression in global context. It means the global variable will be available in macros, following template values of message template and in the action executed by run. For example, a global variable defined in Message Content Template will be also available in Embed Content Template.

{% global six = 3 + 3 %}

In previous example we assigned the result of evaluating the expression 3 + 3 to the variable six and will be available globally.


The do command just evaluates a given expression.

{% do %}

There is not a lot to say about this construct, it might be useful to trigger behaviour from the template by running an object function.


The require is an extension for return command:

{% require expression returning 'Some error just happened!' %}

This command will only return an error if result of evaluating the expression is false according the Type Convert.

You can pass an Embed instead of string (but keep in mind that you shouldn't send it using its send function).


The use command enables additional template behaviour.


Enables template evaluation in strict mode. This means that the Template Engine will return a compilation error in the following cases:

  • Attempt to output an undefined variable;
  • Attempt to access a non-existent property of an object;
  • An attempt to call a non-existent object function or with incorrectly passed arguments.

You can enable this behaviour the following way:

{% use 'strict' %}


The run command is used to run specified Action and optionally pass there some parameters. This operation will interrupt current running action.


This tag is only working in Custom Commands Actions so you can "route" one action to another.

Use action's UUID to run it:

{% run 'aebf9ae8-c62a-4348-b153-a7c0a0173da1' %}


You can get this UUID from action form ifself in the command settings (press "i" icon). Both actions must be the part of the same exact command, e.g. you can't run action of command A from the action of command B.

Use this syntax to pass some parameters to child action:

{% run 'aebf9ae8-c62a-4348-b153-a7c0a0173da1' with { 'param1': 123 } %}
The structure after with is just a map, so you can use a predefined variable instead. Those parameters will be available as part of parameters variable in child action:

{{ parameters.param1 }}
Template above will print 123 in child action.

You can also use the parameters itself in the parent action to pass the data to child action. The following example will do the same thing as previous, just in a different way:

{% do'param1', 123) %}
{% run 'aebf9ae8-c62a-4348-b153-a7c0a0173da1' %}


Actions may run each other in chain up to 3 times. Methods quotas will be shared across the whole chain.

Control Flow#

Template Engine implements basic control flow constructs such as if conditions and for loops.

Conditions — if/elseif/else#

If conditions are the simplest control flow in Template Engine. It supports consecutive elseif conditions and the common else construct too.

{% if (expression) %}
... content if expression is evaluated to true ...
{% elseif (anotherExpression) %}
... content if anotherExpression is evaluated to true ...
{% else %}
... content if none of previous conditions are met ...
{% endif %}

Note that if constructs will only output the content of the first block which condition is evaluated to true according to Type Convert.

In terms of variable scoping, if inner content shares the context with the parent context, this means if conditions can affect variables in the outer scope.

{% set variable = "a" %}
{% if (true) %}
    {% set variable = "b" %}
{% endif %}
{{ variable }}

Previous example will output b which illustrates how scoping works on if conditions by sharing the context with the parent construct.

{% if (1 != 2) %}
    {% return '1 is not 2. Oh wow!' %}
{% endif %}
This text will not be printed because the error.

Previous example will conditionally return an error.

Loops — for#

Template Engine allows iterating over a list or a map.

{# Example with list #}
{% for item in list %}
... content using variable item ...
{% endfor %}

{# Example with map #}
{% for key, value in map %}
... content using variables key and value ...
{% endfor %}

loop variable#

for loops come with an extra variable defined in the context, the loop variable. The loop variable provides a set of useful properties when within a for loop, check below the properties exposed by this variable:

Property Description
length Size of the list or map being iterated
index Current iteration count starting in 1
index0 Current iteration count starting in 0
revindex Remaining number of iterations to reach the end of the list or map, ends in 1
revindex0 Remaining number of iterations to reach the end of the list or map, ends in 0
first Boolean property only true in the first iteration
last Boolean property only true in the last iteration
parent Accessing the parent context
{% for item in [1, 2, 3] %}
    {% if (loop.first) %}
    {% endif %}
{% endfor %}

Previous example will output Start only once.

This loop variable is only bound to the for context, it means this variable will not be visible outside of the for loop scope. If there is a loop variable in the context, it will not be overriden but to access it one need to get the parent context, for example:

{% set loop = 1 %}
{% for item in [1, 2, 3] %}
    {% if (loop.first) %}
        {{ loop.parent.loop }}
        {% set loop = 2 %}
    {% endif %}
{% endfor %}
{{ loop }}

Previous template will print 1 2. Note that setting loop inside the for loop will write to the context, but won't override the for loop bound variable. The value loop variable defined inside the loop is then available outside of the loop scope.

Transformations — transform#

Transformation is a variant of for loops used to transform one list to another. Each transform iteration expects return tag to return new list element accordingly:

{% transform item in [1, 2, 3] as newList %}
    {% return 'element:' ~ item %}
{% endtransform %}
{{ newList }}

Previous example will transform [1, 2, 3] list to ['element:1', 'element:2', 'element:3'] and saves the result to newList variable.

In case then return tag hasn't executed in iteration, corresponding list element will be skipped. Thus, we can use this to filter the list:

{% transform item in [1, 2, 3] as newList %}
    {% if (item != 2) %}
        {% return item %}
    {% endif %}
{% endtransform %}
{{ newList }}

Previous example will transform [1, 2, 3] list to [1, 3], excluding second element from the result according to condition.


Transformations inherits all for loops behaviour, including loop variable and parent context.


Transformations cannot use nested lists/maps, such elements will be excluded from the result. In other words, you can't make list of lists or list of maps.

Also, transformations cannot print anything, output code islands inside transformations will be ignored.


You can interrupt for loops and transformations iterations using break and continue tags.

break will break current and all next iterations of loop:

{% for item in [1, 2, 3, 4] %}
    {% if (item > 2) %}
        {% break %}
    {% endif %}
{% endfor %}

Previous example will output start:1 end:1 start:2 end:2 start:3 as third and all next iterations are being interrupted by item > 2 condition.

continue will only break the current iteration of loop:

{% for item in [1, 2, 3] %}
    {% if (item == 2) %}
        {% continue %}
    {% endif %}
{% endfor %}

Previous example will output start:1 end:1 start:2 start:3 end:3. Note that it lacks of end:2 part as second iterations is being interrupted by item == 2 condition.


The return command will interrupt template evaluation with an error returned to the user.

{% return 'Some error just happened!' %}

You can pass an Embed instead of string (but keep in mind that you shouldn't send it using its send function).

This tag is also used in transformations.



Macro constructs allows the user to reduce template code duplication.

This can be achieved by associating pieces of reusable templates to a specific named macro/endmacro constructs that also allows them to receive arguments.

{% macro macroName(firstArgument, secondArgument, ...) %}
  ... reusable template content ....
{% endmacro %}

Macro Name#

The macro name is an identifier used to reference the macro. It must be unique inside a template and must be defined only once. Attempt to define one more macro with the same name will lead to template execution error.

Macro Arguments#

Macro arguments is a list of identifiers representing input variables which can then be used inside the macro body definition. All arguments are optional, it's up to the caller to provide such arguments or not. You can have macros without arguments at all.


Macros have access to the limited set of variables:

  • Arguments passed to macros;
  • Global variables defined at the moment of macro execution;
  • Default template variables.

Variables defined inside the macro are only available in scope of this macro. Global will be available everywhere.

Execute Macro#

You can execute defined macros just like functions. Think of macros like "user functions".

{% macro fullname(firstName, lastName) %}
  {{ firstName ~ ' ' ~ lastName }}
{% endmacro %}

{{ fullname('Elon', 'Mask') }}

This example has a simple macros to get a full name based on two arguments (first name and last name). Result of macro execution is string built by rendering its template with specified arguments.

Also, you can use return tag in case you want to return specific data from macros (like value of variable or expression):

{% macro fullname(firstName, lastName) %}
  {% return firstName ~ ' ' ~ lastName %}
{% endmacro %}

{{ fullname('Elon', 'Mask') }}

Result of this template is the same as the previous one. Note that "Blahblahblah" text will not be present in result since marco uses return to return specific data.


Macros can't execute another macros.


The filter construct is the way apply functions to a given content. It uses the provided body as the first argument in the specified function.

{% filter lower | capitalize -%}
{%- endfilter %}

Previous example will produce Hello world. As we can see, the filter specified results in the composition of two distinct functions, it will first apply the lower function to the content HELLO WORLD, producing hello world and then apply the capitalize function producing Hello world.


The verbatim tag is useful avoiding the specifics around Template Engine syntax, as it will not try to parse the content.

{% verbatim %}
{{ test }}
{% endverbatim %}

The output of previous template will be {{ test }}.