Configure and Use Dynamic Variables with Pebble Templating

For the complete documentation index, see llms.txt. For a full content snapshot, see llms-full.txt. Append .md to any kestra.io/docs/* URL for plain Markdown.

Variables are key-value pairs that let you reuse values across tasks in a flow, or across multiple flows when stored at the namespace level.

Declaring variables

Define variables under the variables key in a flow and reference them with {{ vars.variable_name }}:

id: hello_world
namespace: company.team
variables:
myvar: hello
numeric_variable: 42
tasks:
- id: log
type: io.kestra.plugin.core.debug.Return
format: "{{ vars.myvar }} world {{ vars.numeric_variable }}"

Rendering

Variables are rendered by the Pebble templating engine, which processes expressions with filters and functions. You can use variables in any task property marked as dynamic.

Dynamic variables

If a variable contains an expression, wrap it with render() when using it in a task — otherwise the expression is treated as a literal string:

id: dynamic_variable
namespace: company.team
variables:
time: "{{ now() }}"
tasks:
- id: log
type: io.kestra.plugin.core.log.Log
message: "{{ render(vars.time) }}"

Set or modify variables at runtime

The SetVariables task updates variables in the execution context. Later tasks see the new values immediately:

id: variables_demo
namespace: company.team
variables:
status: pending
tasks:
- id: update
type: io.kestra.plugin.core.execution.SetVariables
variables:
status: complete
- id: log
type: io.kestra.plugin.core.log.Log
message: "Status is now {{ vars.status }}"

Unset variables

The UnsetVariables task deletes variables from the execution context. It supports dot notation for nested keys:

- id: deleteVariables
type: io.kestra.plugin.core.execution.UnsetVariables
variables:
- state
- ansibleTicket
- nested.child

FAQ

How do I escape a Pebble expression so it is not evaluated?

Use the {% raw %} and {% endraw %} tags. The following returns the string {{ myvar }} literally:

{% raw %}{{ myvar }}{% endraw %}

See Pebble syntax for details.

In what order are inputs and variables resolved?

Inputs are resolved first, before the execution starts — an invalid input value prevents the execution from being created. You can use inputs within variables, but not variables within inputs (see Dynamic Inputs for the exception).

Triggers are resolved like inputs — before the execution starts — so you can reference trigger variables inside variables, but not inputs within triggers unless they have defaults.

Can I transform variables with Pebble expressions?

Yes. Pebble filters and functions work in any dynamic property. For example, use a variable to store a date format and apply it with the date filter:

variables:
DATE_FORMAT: "yyyy-MM-dd"
tasks:
- id: formatted
type: io.kestra.plugin.core.debug.Return
format: "{{ execution.startDate | date(vars.DATE_FORMAT) }}"

See the Expressions reference for the full list of available filters and functions.

Can I use nested variables?

Yes. Use json(item.value).key to access fields on a nested object:

id: vars
namespace: company.myteam
variables:
servers:
- fqn: server01.mydomain.io
user: root
- fqn: server02.mydomain.io
user: guest
tasks:
- id: loop
type: io.kestra.plugin.core.flow.Loop
concurrencyLimit: 0
values: "{{ vars.servers }}"
tasks:
- id: log
type: io.kestra.plugin.core.log.Log
message:
- "{{ item.value }}"
- "{{ json(item.value).fqn }}"
- "{{ json(item.value).user }}"

Was this page helpful?