Inputs
Inputs are dynamic values passed to the flow at runtime.
What are inputs
A flow can be parameterized with inputs, allowing multiple executions of the same flow with different values. Flow inputs are stored in the execution context and accessed with {{ inputs.parameter_name }}
.
You can use inputs to make your tasks more dynamic. For instance, you can use an input to dynamically define the path of a file that needs to be processed within a flow.
You can inspect input values in the Overview tab of the Execution page and set a custom displayName
for each input to make the interface more readable.
Declaring inputs
You can declare as many inputs as necessary for any flow. Inputs can be required or optional.
If an input is required, you must provide a value at runtime or set a defaults
value; otherwise, the execution will not be created.
All inputs are validated when the execution is created; invalid inputs prevent the execution from being created.
If an execution is not created due to invalid or missing inputs, it will not appear in the executions list.
Below is an example flow using several inputs:
id: inputsnamespace: company.team
inputs: - id: string type: STRING defaults: "Hello World!" displayName: "A string input"
- id: optional type: STRING required: false displayName: "An optional string"
- id: int type: INT defaults: 100 displayName: "An integer input"
- id: list_of_int type: ARRAY itemType: INT defaults: [1, 2, 3] displayName: "A list of integers"
- id: bool type: BOOL defaults: true displayName: "A boolean input displayed as a toggle."
- id: float type: FLOAT defaults: 100.12 displayName: "A float input"
- id: dropdown type: SELECT displayName: "A dropdown input" defaults: VALUE_1 values: - VALUE_1 - VALUE_2 - VALUE_3
- id: dropdown_multi type: MULTISELECT values: - VALUE_1 - VALUE_2 - VALUE_3
- id: instant type: DATETIME defaults: "2013-08-09T14:19:00Z" displayName: "A datetime input"
- id: date type: DATE defaults: "2013-10-25" displayName: "A date input"
- id: time type: TIME displayName: "A time input" defaults: "14:19:00"
- id: duration type: DURATION defaults: "PT5M6S" displayName: "A duration input"
- id: file type: FILE displayName: "Upload a file" defaults: nsfile:///hello.txt
- id: json type: JSON displayName: "A JSON input" defaults: | [{"name": "kestra", "rating": "best in class"}]
- id: uri type: URI defaults: "https://huggingface.co/datasets/kestra/datasets/raw/main/csv/orders.csv" displayName: "A URI input"
- id: secret type: SECRET displayName: "A secret input"
- id: yaml type: YAML defaults: - user: john email: john@example.com - user: will email: will@example.com displayName: YAML
- id: nested.string type: STRING defaults: "Hello World!" displayName: "A nested string input"
Starting from Kestra 0.24, the FILE
type supports defaults via the universal file protocol. Use nsfile:///
for namespace files or file:///
for local files.
Note: file:///
works only for explicitly allowed paths. Bind‑mount the host directory into the Kestra container and include that path under kestra.local-files.allowed-paths
in your configuration (e.g., /scripts
). Otherwise, access to the path will be denied for security reasons.
Input types
Inputs in Kestra are strongly typed and validated before starting the flow execution.
Here is the list of supported data types:
STRING
: Any string. Values are passed without parsing; for additional validation, use a regexvalidator
.INT
: Must be a valid integer value (i.e., without any decimals).FLOAT
: Must be a valid float value (i.e., with decimals).SELECT
: Must be a valid string value from a predefined list of values. You can either pass those values directly using thevalues
property or use theexpression
property to fetch the values dynamically from a KV store. Additionally, ifallowCustomValue
is set to true, the user can provide a custom value that is not in the predefined list.
Note: Due to YAML allowing Scalar content to be presented in several formats, the boolean “true” might also be written as “yes” and “false” as “no”. To avoid errors using Yes/No in the SELECT
input type, wrap them in quotation marks to preserve string format: “Yes”, “No”.
MULTISELECT
: Must be one or more valid string values from a predefined list of values. You can either pass those values directly using thevalues
property or use theexpression
property to fetch the values dynamically from a KV store. Additionally, ifallowCustomValue
is set to true, the user can provide a custom value that is not in the predefined list.BOOLEAN
: Must betrue
orfalse
passed as strings.DATETIME
: Must be a valid full ISO 8601 date and time with the timezone expressed in UTC format; pass input of type DATETIME in a string format following the pattern2042-04-02T04:20:42.000Z
.DATE
: Must be a valid full ISO 8601 date without the timezone from a text string such as2042-12-03
.TIME
: Must be a valid full ISO 8601 time without the timezone from a text string such as10:15:30
.DURATION
: Must be a valid full ISO 8601 duration from a text string such asPT5M6S
.FILE
: Either a file uploaded at execution time asContent-Type: multipart/form-data
withContent-Disposition: form-data; name="files"; filename="<input-id>"
(where<input-id>
is the input name), or a default file referenced via the universal file protocol usingnsfile:///path/to/file
(namespace file) orfile:///path/to/file
(local file from an allowed path).JSON
: Must be a valid JSON string and will be converted to a typed form.YAML
: Must be a valid YAML string.URI
: Must be a valid URI and will be kept as a string.SECRET
: Encrypted string stored in the database. It is decrypted at runtime and can be used in all tasks. The value of aSECRET
input is masked in the UI and in the execution context. Note that you need to set the encryption key in your Kestra configuration before using it.ARRAY
: Must be a valid JSON array or a YAML list. TheitemType
property is required to ensure validation of the type of the array items.
All FILE
inputs are automatically uploaded to Kestra’s internal storage and accessible to all tasks. After the upload, the input variable will contain a fully qualified URL of the form kestra:///.../.../
that will be automatically managed by Kestra and can be used as-is within any task.
Input Properties
Below is the list of available properties for all inputs regardless of their types:
id
: The input parameter identifier — this property is important as it’s used to reference the input variables in your flow, e.g.,{{ inputs.user }}
references the input parameter nameduser
.type
: The data type of the input parameter, as described in the previous section.required
: Whether the input is required. Iftrue
and neither a default nor a runtime value is provided, the execution will not be created.defaults
: The default value that is used if no custom input value is provided at runtime; this value must be provided as a string and will be set to the desired data type specified using thetype
property.dependsOn
: Makes the input dependent on other inputs that must be provided first.displayName
: Label shown in the UI instead of theid
.description
: Markdown description for the input.expression
: Use a pebble expression as a value — e.g.,expression: "{{ kv('SELECT_VALUES') }}"
.autoSelectFirst
: A boolean property to auto-select the first list value in the dropdown as a default value (only usable forSELECT
andMULTISELECT
input types). This way, you don’t need to explicitly set anydefaults
for that property.
Input validation
Kestra validates the type
of each input. In addition to the type validation, some input types can be configured with validation rules that are enforced at execution time.
STRING
: Avalidator
property allows the addition of a validation regex.INT
:min
andmax
define the allowed range.FLOAT
:min
andmax
define the allowed range.DURATION
:min
andmax
define the allowed range.DATE
:after
andbefore
properties help you ensure that the input value is within the allowed date range.TIME
:after
andbefore
properties help you ensure that the input value is within the allowed time range.DATETIME
:after
andbefore
properties help you ensure that the input value is within the allowed date and time range.
Example: use input validators in your flows
To ensure that your input value is within a certain integer
value range, you can use the min
and max
properties. Similarly, to ensure that your string input matches a regex pattern, you can provide a custom regex validator
. The following flow demonstrates how this can be accomplished:
id: regex_inputnamespace: company.team
inputs: - id: age type: INT defaults: 42 required: false min: 18 max: 64
- id: user type: STRING defaults: student required: false validator: ^student(\d+)?$
- id: float type: FLOAT defaults: 3.2 min: 0.2 max: 5.3
- id: duration type: DURATION min: "PT5M6S" max: "PT12H58M46S"
- id: date type: DATE defaults: "2024-04-12" after: "2024-04-10" before: "2024-04-15"
- id: time type: TIME after: "11:01:01" before: "11:04:01"
- id: datetime type: DATETIME defaults: "2024-04-13T14:17:00Z" after: "2024-04-10T14:19:00Z" before: "2024-04-15T14:19:00Z"
tasks: - id: validator type: io.kestra.plugin.core.log.Log message: User {{ inputs.user }}, age {{ inputs.age }}
The age
, float
, and duration
input must be within a valid range between min
and max
values. Specifically for the age
input, we specify that this input is by default set to 42, but it can be overwritten at runtime to a value between 18 and 64. If you attempt to execute the flow with the age
input set to 17 or 65, the validation will fail and the execution won’t start.
Similarly, the Regex expression ^student(\d+)?$
is used to validate that the input argument user
of type STRING follows the following pattern:
^student
: This part of the regex asserts that the string must begin with the lowercase string valuestudent
.\d
: This part of the regex matches any digit (0-9).+
: This part of the regex asserts that there is one or more of the preceding token (i.e., one or more digits are allowed after the valuestudent
).()?
: The parentheses group the digits together, and the question mark makes the entire group optional — this means that the digits after the wordstudent
are optional.$
: This part of the regex asserts the end of the string. This ensures that the string doesn’t contain any additional characters after the optional digits.
With this pattern:
- “student” is a match.
- “student123” is a match.
- “studentabc” is not a match because “abc” isn’t a sequence of digits.
- “student123abc” is not a match because no characters are allowed after
student
and the optional digits.
Lastly, the date
, time
, and datetime
inputs must be within a valid range between after
and before
. In the date
example, the date provided must be between 10th April 2024 and 15th April 2024. Anything outside of this range will fail and the execution won’t start.
Try running this flow with various inputs or adjust the regex pattern to see how the input validation works.
Nested Inputs
Using a .
in an input id
creates a nested input.
Here’s an example that includes 2 nested inputs:
id: nested_inputsnamespace: company.team
inputs: - id: nested.string type: STRING required: false
- id: nested.int type: INT
tasks: - id: log_inputs type: io.kestra.plugin.core.log.Log message: "{{ inputs.nested.string }} and {{ inputs.nested.int }}"
You can access the first input value using {{ inputs.nested.string }}
. This provides type validation for nested inputs without resorting to raw JSON (JSON inputs are passed as strings).
Array Inputs
Array inputs are used to pass a list of values to a flow. The itemType
property is required to ensure validation of the type of the array items.
This is useful when you want the user triggering the workflow to provide multiple values of a specific type, for example, a list of integers, strings, booleans, datetimes, etc. You can provide the default values as a JSON array or as a YAML list — both are supported.
id: array_demonamespace: company.team
inputs: - id: my_numbers_json_list type: ARRAY itemType: INT defaults: [1, 2, 3]
- id: my_numbers_yaml_list type: ARRAY itemType: INT defaults: - 1 - 2 - 3
tasks: - id: print_status type: io.kestra.plugin.core.log.Log message: received inputs {{ inputs }}
Below is how the array inputs are rendered in the UI when you create an execution:
Use an input value in a flow
Inputs are available via {{ inputs.name }}
or {{ inputs['name'] }}
. If an input id
contains characters like -
, use the bracket form: {{ inputs['name-example'] }}
.
For example, if you declare the following inputs:
inputs: - id: mystring type: STRING required: true
- id: my-file type: FILE
You can use the value of the input mystring
inside dynamic task properties with {{ inputs.mystring }}
but my-file
would have to use {{ inputs['my-file'] }}
because of the hyphen (-
).
We can see a full example below where inputFiles
property is set to {{ inputs['my-file'] }}
:
id: input_filesnamespace: company.team
description: This flow shows how to pass files between inputs and tasks in Shell scripts.
inputs: - id: my-file type: FILE
tasks: - id: rename type: io.kestra.plugin.scripts.shell.Commands commands: - mv file.tmp output.tmp inputFiles: file.tmp: "{{ inputs['my-file'] }}" outputFiles: - "*.tmp"
As of 0.14, inputs are no longer rendered recursively. Learn more about this change—and how to adjust behavior in the 0.14 migration guide.
Set input values at flow execution
When executing a flow with inputs, you must provide all required inputs (unless a default is defined) for the execution to be created.
Let’s consider the following example that defines multiple inputs:
id: kestra_inputsnamespace: company.team
inputs: - id: string type: STRING defaults: hello
- id: optional type: STRING required: false
- id: int type: INT
- id: float type: FLOAT
- id: instant type: DATETIME
- id: file type: FILE
Here, string
and optional
can be omitted because string
has a default and optional
is not required. All other inputs must be specified at runtime.
Set inputs from the web UI
When creating an execution from the web UI, you must set the inputs in the UI form. Kestra’s UI generates a dedicated form based on your inputs
definition. For example, datetime input properties have a date picker.
The input form for the inputs above looks as follows:
Once the inputs are set, you can trigger an execution of the flow.
Set inputs when executing the flow using the API
To create an execution with these inputs using the API, we can use the curl
command to make an API request:
curl -v "http://localhost:8080/api/v1/main/executions/example/kestra-inputs" \ -H "Transfer-Encoding:chunked" \ -H "Content-Type:multipart/form-data" \ -F string="a string" \ -F optional="an optional string" \ -F int=1 \ -F float=1.255 \ -F instant="2023-12-24T23:00:00.000Z" \ -F "files=@/tmp/128M.txt;filename=file"
Send files as multipart/form-data
under the files
field with filename="<input-id>"
, where <input-id>
is the input name.
Set inputs when executing the flow in Python
To create an execution with these inputs in Python, you can use the following script:
import ioimport requestsfrom kestra import Flow
flow = Flow()
with open('/tmp/example.txt', 'rb') as fh: flow.execute('example', 'kestra-inputs', {'string': 'a string', 'optional': 'an optional string', 'int': 1, 'float': str(1.255), 'instant': '2020-01-14T23:00:00.000Z', 'files': ('file', fh, 'text/plain')})
Wrap floats with str()
; otherwise, a bytes-like object error may occur when sending a file input.
You can also use the requests
library in Python to make requests to the Kestra API. Here’s an example to execute a flow with multiple inputs:
import ioimport requestsfrom requests_toolbelt.multipart.encoder import MultipartEncoder
with open("/tmp/128M.txt", 'rb') as fh: url = f"http://kestra:8080/api/v1/main/executions/io.kestra.docs/my-flow" mp_encoder = MultipartEncoder(fields={ "string": "a string", "optional": "an optional string", "int": 1, "float": 1.255, "instant": "2020-01-14T23:00:00.000Z", "files": ("file", fh, "text/plain") }) result = requests.post( url, data=mp_encoder, headers={"Content-Type": mp_encoder.content_type}, )
Set inputs when executing the flow in Java
To create an execution with these inputs in Java (with Apache Http Client 5), you can use the following script:
import org.apache.hc.client5.http.classic.methods.HttpPost;import org.apache.hc.client5.http.entity.mime.FileBody;import org.apache.hc.client5.http.entity.mime.MultipartEntityBuilder;import org.apache.hc.client5.http.entity.mime.StringBody;import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse;import org.apache.hc.client5.http.impl.classic.HttpClientBuilder;import org.apache.hc.core5.http.ContentType;import org.apache.hc.core5.http.HttpEntity;
import java.io.File;
class Application { public static void main(String[] args) { HttpEntity multipartEntity = MultipartEntityBuilder.create() .addPart("string", new StringBody("test", ContentType.DEFAULT_TEXT)) .addPart("int", new StringBody("1", ContentType.DEFAULT_TEXT)) .addPart("files", new FileBody(new File("/tmp/test.csv"), ContentType.DEFAULT_TEXT, "file")) .build();
try (CloseableHttpClient httpclient = HttpClientBuilder.create().build()) { HttpPost request = new HttpPost("http://kestra:8080/api/v1/main/executions/com.kestra.lde/inputs"); request.setEntity(multipartEntity);
CloseableHttpResponse response = httpclient.execute(request);
System.out.println("Response " + response); } catch (Exception e) { throw new RuntimeException(e); } }}
Difference between inputs and variables
[Variables] are similar to constants. They behave like inputs during execution but cannot be overridden once the execution starts. Variables must be defined before execution, whereas inputs can be set at execution time.
Variables are best suited for values that you don’t want to change and are used in multiple places within the flow. For example, a URL you use for an API request that won’t change is best as a variable whereas an email address that changes every time you execute your flow is best as an input.
Dynamic inputs
Inputs in Kestra are strongly typed. Currently, you cannot enforce strong types and simultaneously use dynamically rendered Pebble expressions. However, you can use Pebble expressions in default values within STRING inputs.
This example wouldn’t work:
id: testnamespace: company.team
inputs: - id: date type: DATETIME defaults: "{{ now() }}"
tasks: - id: print_date type: io.kestra.plugin.core.log.Log message: hello on {{ inputs.date }}
However, if you change the input type to STRING
, you can use Pebble expressions such as {{ now() }}
in the default value:
id: testnamespace: company.team
inputs: - id: date type: STRING defaults: "{{ now() }}"
tasks: - id: print_date type: io.kestra.plugin.core.log.Log message: hello on {{ render(inputs.date) }}
As of 0.14, inputs are no longer rendered recursively. Therefore, you need to use the {{ render(inputs.date) }}
syntax to render the Pebble expression specified within the STRING input value. This improves security by preventing the execution of arbitrary code within the Pebble expression.
You can read more about this change in the Migration Guide.
Dynamic Inputs with HTTP function
With the http()
function, you can make SELECT
and MULTISELECT
inputs dynamic by fetching options from an external API. This proves valuable when your data used in dropdowns changes frequently or when you already have an API serving that data for existing applications.
The example below demonstrates how to create a flow with two dynamic dropdowns: one for selecting a product category and another for selecting a product from that category. The first dropdown fetches the product categories from an external HTTP API. The second dropdown makes another HTTP call to dynamically retrieve products matching the selected category.
id: dynamic_dropdownsnamespace: company.teaminputs: - id: category type: SELECT expression: "{{ http(uri = 'https://dummyjson.com/products/categories') | jq('.[].slug') }}" - id: product type: SELECT dependsOn: inputs: - category expression: "{{ http(uri = 'https://dummyjson.com/products/category/' + inputs.category) | jq('.products[].title') }}"tasks: - id: display_selection type: io.kestra.plugin.core.log.Log message: | You selected Category: {{ inputs.category }} And Product: {{ inputs.product }}
Conditional inputs for interactive workflows
You can set up inputs that depend on other inputs, letting further inputs be conditionally displayed based on user choices. This is useful for use cases such as approval workflows or dynamic resource provisioning.
How it works
Create inputs that change based on other inputs using the dependsOn
and condition
properties. The example below shows different inputs appearing based on the selected resource type:
id: request_resourcesnamespace: company.team
inputs: - id: resource_type displayName: Resource type type: SELECT values: - Access permissions - SaaS application - Development tool - Cloud VM
- id: access_permissions displayName: Access permissions type: SELECT expression: "{{ kv('access_permissions') }}" dependsOn: inputs: - resource_type condition: "{{ inputs.resource_type == 'Access permissions' }}"
- id: saas_applications displayName: SaaS spplication type: MULTISELECT expression: "{{ kv('saas_applications') }}" dependsOn: inputs: - resource_type condition: "{{ inputs.resource_type == 'SaaS application' }}"
- id: cloud_provider displayName: Cloud provider type: SELECT values: - AWS - GCP - Azure dependsOn: inputs: - resource_type condition: "{{ inputs.resource_type == 'Cloud VM' }}"
- id: cloud_vms displayName: Cloud VM type: SELECT expression: "{{ kv('cloud_vms')[inputs.cloud_provider] }}" dependsOn: inputs: - resource_type - cloud_provider condition: "{{ inputs.resource_type == 'Cloud VM' }}"
In this example:
- The
resource_type
input controls which additional inputs (such asaccess_permissions
,saas_applications
, andcloud_vms
) appear. dependsOn
links inputs;condition
defines when to display the related input.
Before running the flow, set up the key–value pairs for each input. Expand the example below to add all key–value pairs with a helper flow.
Flow adding key-value pairs
id: add_kv_pairsnamespace: company.team
tasks: - id: access_permissions type: io.kestra.plugin.core.kv.Set key: "{{ task.id }}" kvType: JSON value: | ["Admin", "Developer", "Editor", "Launcher", "Viewer"]
- id: saas_applications type: io.kestra.plugin.core.kv.Set key: "{{ task.id }}" kvType: JSON value: | ["Slack", "Notion", "HubSpot", "GitHub", "Jira"]
- id: development_tools type: io.kestra.plugin.core.kv.Set key: "{{ task.id }}" kvType: JSON value: | ["Cursor", "IntelliJ IDEA", "PyCharm Professional", "DataGrip"]
- id: cloud_vms type: io.kestra.plugin.core.kv.Set key: "{{ task.id }}" kvType: JSON value: | { "AWS": ["t2.micro", "t2.small", "t2.medium", "t2.large"], "GCP": ["f1-micro", "g1-small", "n1-standard-1", "n1-standard-2"], "Azure": ["Standard_B1s", "Standard_B1ms", "Standard_B2s", "Standard_B2ms"] }
- id: cloud_regions type: io.kestra.plugin.core.kv.Set key: "{{ task.id }}" kvType: JSON value: | { "AWS": ["us-east-1", "us-west-1", "us-west-2", "eu-west-1"], "GCP": ["us-central1", "us-east1", "us-west1", "europe-west1"], "Azure": ["eastus", "westus", "centralus", "northcentralus"] }
You can also add these key–value pairs via the API or the UI.
Custom values in SELECT and MULTISELECT inputs
If the predefined dropdown values do not fit a user’s needs, set allowCustomValue
to true
to allow custom entries. This lets you offer defaults while still accepting user-provided values.
In the example below, cloud_provider
lets users select a common provider (AWS, GCP, Azure) or enter a custom value (e.g., Oracle Cloud).
id: custom_valuesnamespace: company.team
inputs: - id: cloud_provider displayName: Cloud provider type: SELECT allowCustomValue: true values: - AWS - GCP - Azure
tasks: - id: print_status type: io.kestra.plugin.core.log.Log message: Selected cloud provider {{ inputs.cloud_provider }}