Dynamically Render Variables, Inputs and Outputs with Pebble

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.

Pebble is a Java templating engine inspired by Twig and similar to Jinja. Kestra uses it to dynamically render variables, inputs, and outputs within the execution context. For the full list of available variables, filters, and functions, see the Expressions reference.

Reading inputs

Access input values in tasks using the inputs variable:

id: input_string
namespace: company.team
inputs:
- id: name
type: STRING
tasks:
- id: say_hello
type: io.kestra.plugin.core.log.Log
message: "Hello 👋, my name is {{ inputs.name }}"

Reading task outputs

Most tasks expose output values accessible as outputs.<task_id>.<output_name>. The available outputs for each task are listed in its plugin documentation.

This example reads the value output of the Return task in a downstream Log task:

id: input_string
namespace: company.team
inputs:
- id: name
type: STRING
tasks:
- id: say_hello
type: io.kestra.plugin.core.debug.Return
format: "Hello 👋, my name is {{ inputs.name }}"
- id: can_you_repeat
type: io.kestra.plugin.core.log.Log
message: '{{ outputs.say_hello.value }}'

Dynamically render a task with TemplatedTask

TemplatedTask lets you fully template all task properties using Pebble — including properties that are not natively dynamic. This example uses TemplatedTask to create a Databricks job with inputs controlling the cluster, task key, and wait time:

id: templated_databricks_job
namespace: company.team
inputs:
- id: host
type: STRING
- id: clusterId
type: STRING
- id: taskKey
type: STRING
- id: pythonFile
type: STRING
- id: sparkPythonTaskSource
type: ENUM
defaults: WORKSPACE
values:
- GIT
- WORKSPACE
- id: maxWaitTime
type: STRING
defaults: "PT30M"
tasks:
- id: templated_spark_job
type: io.kestra.plugin.core.templating.TemplatedTask
spec: |
type: io.kestra.plugin.databricks.job.CreateJob
authentication:
token: "{{ secret('DATABRICKS_API_TOKEN') }}"
host: "{{ inputs.host }}"
jobTasks:
- existingClusterId: "{{ inputs.clusterId }}"
taskKey: "{{ inputs.taskKey }}"
sparkPythonTask:
pythonFile: "{{ inputs.pythonFile }}"
sparkPythonTaskSource: "{{ inputs.sparkPythonTaskSource }}"
waitForCompletion: "{{ inputs.maxWaitTime }}"

waitForCompletion and sparkPythonTaskSource are not natively dynamic properties — TemplatedTask makes it possible to drive them from inputs.


Date formatting

Use the date filter to format date values inline: '{{ inputs.my_date | date("yyyyMMdd") }}'

Coalesce operator to conditionally use trigger or execution date

Scheduled flows can use trigger.date to get the trigger’s date, but that variable is not set on manual executions. Use the coalesce operator ?? to fall back to execution.startDate when the trigger date is unavailable:

id: pebble_date_trigger
namespace: company.team
tasks:
- id: return_date
type: io.kestra.plugin.core.debug.Return
format: '{{ trigger.date ?? execution.startDate | date("yyyy-MM-dd") }}'
triggers:
- id: schedule
type: io.kestra.plugin.core.trigger.Schedule
cron: "* * * * *"

Parsing objects and lists using jq

Use the jq filter to slice, filter, and transform nested objects or lists returned by task outputs — similar to how sed, awk, and grep work on strings.

id: object_example
namespace: company.team
inputs:
- id: data
type: JSON
defaults: '{"value": [1, 2, 3]}'
tasks:
- id: hello
type: io.kestra.plugin.core.log.Log
message: "{{ inputs.data }}"

The expression {{ inputs.data.value }} returns the list [1, 2, 3]

The expression {{ inputs.data.value | jq(".[1]") | first }} returns 2.

jq(".[1]") accesses the second value of the list and returns an array with one element. We then use first to access the value itself.

{{ inputs | jq(".data.value[1]") | first }} also works — jq can parse any object in the Kestra context.

Use the Debug Expression button in the Outputs tab of an execution to troubleshoot complex expressions and validate how objects will be parsed.

Using conditions in Pebble

Tasks like If and Switch accept Pebble expressions as conditions, letting you branch on inputs or previous task outputs:

id: test-object
namespace: company.team
inputs:
- id: data
type: JSON
defaults: '{"value": [1, 2, 3]}'
tasks:
- id: if
type: io.kestra.plugin.core.flow.If
condition: '{{ inputs.data.value | jq(".[2]") | first == 3 }}'
then:
- id: when_true
type: io.kestra.plugin.core.log.Log
message: 'Condition was true'
else:
- id: when_false
type: io.kestra.plugin.core.log.Log
message: 'Condition was false'

Was this page helpful?