Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
521a2b2
docs(release): create 1.4.0 release branch
aj-emerich Mar 9, 2026
7ccec14
Merge branch 'main' into docs/1.4.0-release
aj-emerich Mar 18, 2026
addb3cc
docs(prototype): split config and expression pages (#4241)
aj-emerich Mar 18, 2026
8a2979f
docs(function-reference): recover credential()
aj-emerich Mar 18, 2026
84a938c
docs(plugin-defaults): add cpu cores configuration and update defaults
aj-emerich Mar 18, 2026
4af0868
docs(password-policy): update configuration
aj-emerich Mar 18, 2026
33ecfa3
docs(script-commands-triggers): add to polling and language how-to gu…
aj-emerich Mar 19, 2026
1f48316
docs(git-blueprints): add Blueprint Sync and Push docs
aj-emerich Mar 31, 2026
984f3d0
docs(PurgeLogs): add new flags
aj-emerich Mar 31, 2026
1b00371
docs(agent-skills): add tools section and skill example
aj-emerich Mar 31, 2026
89cf5cd
docs(allowed-namespaces): match current ui
aj-emerich Apr 2, 2026
e4b9178
Merge branch 'main' into docs/1.4.0-release
aj-emerich Apr 13, 2026
4c7f58c
docs(PurgeLogs): add batch size
aj-emerich Apr 13, 2026
1713323
Merge branch 'main' into docs/2.0.0-release
aj-emerich Apr 13, 2026
56cc53d
docs(executor-metrics): add new metrics
aj-emerich Apr 13, 2026
a0323ff
Merge branch 'main' into docs/2.0.0-release
aj-emerich Apr 13, 2026
b120009
docs(expressions): bring back the monolith page (#4564)
aj-emerich Apr 13, 2026
fb4fb1e
Merge branch 'main' into docs/2.0.0-release
aj-emerich Apr 13, 2026
184a5ca
docs(runif-when): add migration guide
aj-emerich Apr 13, 2026
217f939
docs(when): use when instead of conditions and runIf
aj-emerich Apr 13, 2026
6ea6be4
docs(TRACEPARENT): add tracing for scripts
aj-emerich Apr 13, 2026
47a2389
docs(tls/mtls): update enterprise config
aj-emerich Apr 16, 2026
cb26b85
Merge branch 'main' into docs/2.0.0-release
aj-emerich Apr 16, 2026
3cc7341
docs(ai-agents): mention usage metric emits
aj-emerich Apr 17, 2026
d334f40
Merge branch 'main' into docs/2.0.0-release
aj-emerich Apr 20, 2026
f30039a
docs(ldap): add mode property controls
aj-emerich Apr 20, 2026
84749d3
docs(checks.conditions): conditions now when
aj-emerich Apr 20, 2026
f695967
docs(trigger-redesign)
aj-emerich Apr 20, 2026
4c5b9ce
docs(trigger-redesign): Enforce better style
aj-emerich Apr 20, 2026
f21ff0d
docs(loop): add new loop task
aj-emerich Apr 20, 2026
44ffb44
docs(checks): improve page
aj-emerich Apr 20, 2026
6446eac
Merge branch 'main' into docs/2.0.0-release
aj-emerich Apr 21, 2026
427cc66
Merge branch 'main' into docs/2.0.0-release
aj-emerich Apr 21, 2026
e2c7670
docs(2.0-migration-guide): add call out and links to metadata migrations
aj-emerich Apr 21, 2026
3e1f8fd
docs(trigger-redesign): fix flows and add more to migration guide
aj-emerich Apr 21, 2026
25cc015
docs(migration-guides): further polish
aj-emerich Apr 22, 2026
57e97c1
docs(worker-groups): dynamic resolve to null
aj-emerich Apr 22, 2026
aad45e7
docs(migration-guide): ForEach^ to Loop
aj-emerich Apr 24, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/contents/blogs/release-1-2/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -360,7 +360,7 @@ id: vm_provisioning
namespace: company.team

checks:
- condition: "{{ kv('VMs') | length < 2 }}"
- when: "{{ kv('VMs') | length < 2 }}"
message: "You have provisioned too many VMs"
style: ERROR
behavior: BLOCK_EXECUTION
Expand Down
5 changes: 2 additions & 3 deletions src/contents/docs/03.tutorial/04.triggers/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,9 @@ triggers:

- id: flow_trigger
type: io.kestra.plugin.core.trigger.Flow
conditions:
- type: io.kestra.plugin.core.condition.ExecutionFlow
dependsOn:
- flowId: first_flow
namespace: company.team
flowId: first_flow
```

:::alert{type="info"}
Expand Down
11 changes: 3 additions & 8 deletions src/contents/docs/03.tutorial/06.errors/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -145,14 +145,9 @@ tasks:
triggers:
- id: listen
type: io.kestra.plugin.core.trigger.Flow
conditions:
- type: io.kestra.plugin.core.condition.ExecutionStatus
in:
- FAILED
- WARNING
- type: io.kestra.plugin.core.condition.ExecutionNamespace
namespace: company.team
prefix: true
dependsOn:
- states: [FAILED, WARNING]
when: "{{ namespace | startsWith('company.team') }}"
```

Adding this flow ensures you receive a Slack alert for any flow failure in the `company.team` namespace.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,10 @@ For more details, check out the [If Task documentation](/plugins/core/flow/io.ke

### ForEach

:::alert{type="warning"}
`ForEach` is removed in Kestra 2.0. Use the [`Loop` task](#loop) instead. See the [ForEach → Loop migration guide](../../../11.migration-guide/v2.0.0/foreach-loop/index.md).
:::

This task executes a group of tasks for each value in the list.

In the following example, the variable is static, but it could also be generated from a previous task output, starting any number of subtasks.
Expand Down Expand Up @@ -171,6 +175,7 @@ In this execution, you can access:

- The iteration value i.e., the index of a loop (the loop index starts at 0) using the syntax `{{ taskrun.iteration }}`
- The output of a sibling task using the syntax `{{ outputs.sibling[taskrun.value].value }}`
- The output from a previous iteration using `iterationOutput()`, for example `{{ iterationOutput() }}` for the same task or `{{ iterationOutput('taskId', taskrun.iteration - 1) }}` for a sibling task in an earlier iteration

---

Expand Down Expand Up @@ -208,6 +213,10 @@ For more details, refer to the [ForEach Task documentation](/plugins/core/flow/i

### ForEachItem

:::alert{type="warning"}
`ForEachItem` is removed in Kestra 2.0. Use the [`Loop` task](#loop) with a URI value instead. See the [ForEach → Loop migration guide](../../../11.migration-guide/v2.0.0/foreach-loop/index.md).
:::

This task iterates over a list of items and runs a subflow for each item, or for each batch of items.

```yaml
Expand Down Expand Up @@ -278,6 +287,189 @@ Read more about performance optimization in our [best practices guides](../../..

---

### Loop

The `Loop` task iterates over a set of values and runs a set of child tasks for each item. Unlike `ForEach`, each iteration runs in an isolated sub-execution with its own context.

`values` accepts a list, a JSON array string, a map, or an ION file URI. When `values` is a URI, Kestra performs one iteration per line of the file.

```yaml
id: loop-basic
namespace: company.team

tasks:
- id: loop
type: io.kestra.plugin.core.flow.Loop
values: ["value 1", "value 2", "value 3"]
tasks:
- id: log
type: io.kestra.plugin.core.log.Log
message: "index={{ item.index }} value={{ item.value }}"
```

Inside each iteration, use the `item` variable to access the iteration context:

| Expression | Description |
|---|---|
| `{{ item.index }}` | Zero-based iteration index |
| `{{ item.value }}` | Current iteration value |
| `{{ item.key }}` | Current map key when `values` is a map; not set for list or URI values |
| `{{ item.parent.index }}` | Index of the nearest enclosing loop (nested loops only) |
| `{{ item.parent.value }}` | Value of the nearest enclosing loop (nested loops only) |
| `{{ item.parents[n].value }}` | Value of the nth ancestor loop, counting from innermost |

For more details on `item`, see [loop iteration context](../../../expressions/index.mdx#loop-iteration-context) in the expressions reference.

#### Concurrent execution

By default (`concurrencyLimit: 1`), iterations run one at a time in order. Set `concurrencyLimit` to a higher value to run multiple iterations simultaneously, or `0` for no limit.

```yaml
tasks:
- id: loop
type: io.kestra.plugin.core.flow.Loop
values: [1, 2, 3, 4, 5]
concurrencyLimit: 3
tasks:
- id: log
type: io.kestra.plugin.core.log.Log
message: "Processing {{ item.value }} (index={{ item.index }})"
```

#### Failure propagation

By default (`transmitFailed: true`), a failed iteration causes the Loop task itself to fail. Set `transmitFailed: false` to let the loop continue even when individual iterations fail.

```yaml
tasks:
- id: loop
type: io.kestra.plugin.core.flow.Loop
values: ["ok", "fail", "ok"]
transmitFailed: false
tasks:
- id: maybe_fail
type: io.kestra.plugin.core.flow.If
condition: '{{ item.value == "fail" }}'
then:
- id: do_fail
type: io.kestra.plugin.core.execution.Fail
else:
- id: success
type: io.kestra.plugin.core.log.Log
message: "OK: {{ item.value }}"
```

#### Nested loops

Loops can be nested to any depth. Because `item` is bound to the loop execution rather than individual task runs, flowable tasks nested inside a loop can access `item` directly without a `parent.` prefix.

```yaml
tasks:
- id: outer
type: io.kestra.plugin.core.flow.Loop
values: [1, 2, 3]
tasks:
- id: inner
type: io.kestra.plugin.core.flow.Loop
values: ["a", "b"]
tasks:
- id: log
type: io.kestra.plugin.core.log.Log
message: "outer={{ item.parent.value }} inner={{ item.value }}"
```

For deeper hierarchies, `item.parents[0]` is the immediate parent loop, `item.parents[1]` is the next outer loop, and so on.

#### Loop outputs

By default, task outputs produced inside a loop are not accessible to tasks that run after the loop. Use the `outputs` property on the Loop task to explicitly declare which values to expose.

```yaml
id: loop-outputs
namespace: company.team

tasks:
- id: loop
type: io.kestra.plugin.core.flow.Loop
values: ["a", "b", "c"]
outputs:
- id: result
type: STRING
value: "{{ outputs.process.value }}"
tasks:
- id: process
type: io.kestra.plugin.core.debug.Return
format: "processed {{ item.value }}"

- id: summary
type: io.kestra.plugin.core.log.Log
message: "Loop ran {{ outputs.loop.iterationCount }} iterations"
```

The loop also exposes monitoring outputs regardless of whether `outputs` is declared:

| Output | Description |
|---|---|
| `iterationCount` | Total number of iterations |
| `runningIterations` | Iterations still in progress |
| `terminatedIterations` | Iterations that have finished |

The `fetchType` property controls how iteration outputs are collected: `FETCH` returns them directly in the execution context, `STORE` writes them to internal storage as a URI, and `AUTO` (the default) chooses based on whether `values` is a URI.

#### Accessing loop outputs in a script task

The following example runs a Python task inside a loop to compute a value, then reads the collected results in a subsequent Python task using the monitoring output and the Kestra Python SDK.

```yaml
id: loop-python-outputs
namespace: company.team

tasks:
- id: process_items
type: io.kestra.plugin.core.flow.Loop
values: [1, 2, 3, 4, 5]
outputs:
- id: squared
type: INT
value: "{{ outputs.compute.vars.result }}"
tasks:
- id: compute
type: io.kestra.plugin.scripts.python.Script
dependencies:
- kestra
script: |
from kestra import Kestra
n = {{ item.value }}
Kestra.outputs({"result": n * n})

- id: analyze
type: io.kestra.plugin.scripts.python.Script
dependencies:
- kestra
script: |
from kestra import Kestra

iteration_count = {{ outputs.process_items.iterationCount }}

# outputs.process_items.outputs is a map keyed by iteration value string:
# {"1": {"squared": 1}, "2": {"squared": 4}, "3": {"squared": 9}, ...}
all_outputs = {{ outputs.process_items.outputs | toJson }}

squared_values = [v["squared"] for v in all_outputs.values()]

print(f"Processed {iteration_count} items")
print(f"Squared values: {squared_values}")
print(f"Sum of squares: {sum(squared_values)}")

Kestra.outputs({"total": sum(squared_values)})
```

`outputs.process_items.iterationCount` is always available after the loop finishes. `outputs.process_items.outputs` is a map keyed by iteration value string — for `values: [1, 2, 3, 4, 5]`, the keys are `"1"`, `"2"`, `"3"`, `"4"`, `"5"`. To access a single iteration's output directly in an expression, use `outputs.process_items.outputs['1'].squared`.

For more details, see the [Loop task documentation](/plugins/core/flow/io.kestra.plugin.core.flow.loop).

---

### LoopUntil

`LoopUntil` runs a group of tasks repeatedly until a boolean condition evaluates to `true`. After each iteration, the task evaluates the `condition` expression; if it evaluates to `false`, the block is executed again after the configured interval.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,8 @@ tasks:
```
This produces two separate log entries, one with `1` and the other with `2`.

In `ForEach`, `taskrun.iteration` is often paired with `iterationOutput()` when you need to read a previous iteration's result. For example, `{{ iterationOutput('my_task', taskrun.iteration - 1) }}` fetches the output of `my_task` from the previous loop index.

### Parent task run values

You can also use the `{{ parent.taskrun.value }}` expression to access a task run value from a parent task within nested flowable child tasks:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ All tasks share the following core properties:
| `description` | Your custom [documentation](../../../05.workflow-components/15.descriptions/index.md) of what the task does |
| `retry` | How often should the task be retried in case of a failure, and the [type of retry strategy](../../../05.workflow-components/12.retries/index.md) |
| `timeout` | The [maximum time allowed](../../../05.workflow-components/13.timeout/index.md) for the task to complete expressed in [ISO 8601 Durations](https://en.wikipedia.org/wiki/ISO_8601#Durations) |
| `runIf` | Skip a task if the provided condition evaluates to false |
| `when` | Skip a task if the provided condition evaluates to false |
| `disabled` | A boolean flag indicating whether the task is [disabled or not](../../../05.workflow-components/16.disabled/index.md); if set to `true`, the task will be skipped during the execution |
| `workerGroup` | The [group of workers](../../07.enterprise/04.scalability/worker-group/index.md) (EE-only) that are eligible to execute the task; you can specify a `workerGroup.key` and a `workerGroup.fallback` (the default is `WAIT`) |
| `allowFailure` | A boolean flag allowing to continue the execution even if this task fails |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -233,11 +233,7 @@ triggers:
backfill:
start: 2023-11-11T00:00:00Z
cron: "0 11 * * MON" # at 11:00 every Monday
conditions: # only first Monday of the month
- type: io.kestra.plugin.core.condition.DayWeekInMonth
date: "{{ trigger.date }}"
dayOfWeek: "MONDAY"
dayInMonth: "FIRST"
when: "{{ isDayWeekInMonth(trigger.date, 'MONDAY', 'FIRST') }}" # only first Monday of the month
```


Expand Down
28 changes: 27 additions & 1 deletion src/contents/docs/05.workflow-components/06.outputs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ tasks:
- id: main
type: io.kestra.plugin.core.debug.Return
format: Hello World!
runIf: "{{ inputs.run_task }}"
when: "{{ inputs.run_task }}"

- id: fallback
type: io.kestra.plugin.core.debug.Return
Expand Down Expand Up @@ -360,6 +360,32 @@ tasks:

You can also use the `currentEachOutput` function to access the current tree task. See [Function Reference](../../expressions/index.mdx#function-reference) for more details.

If you need the output from a previous iteration of the same task, or from a sibling task in a previous iteration, use `iterationOutput()` instead.

For example, this flow builds a running total by reading the previous iteration's output:

```yaml
id: foreach_prefix_sum
namespace: company.team

tasks:
- id: foreach
type: io.kestra.plugin.core.flow.ForEach
values: ["100", "200", "300"]
tasks:
- id: prefix_sum
type: io.kestra.plugin.core.debug.Return
format: >-
{% set idx = taskrun.iteration %}
{% if idx == 0 %}
{{ taskrun.value | trim | number }}
{% else %}
{{ iterationOutput('prefix_sum', idx - 1) | trim | number + taskrun.value | trim | number }}
{% endif %}
```

`iterationOutput()` defaults to the current task and the previous iteration, so `{{ iterationOutput() }}` is equivalent to reading the current task's output from `taskrun.iteration - 1`.

:::alert{type="warning"}
Accessing sibling task outputs is impossible on [Parallel](/plugins/core/flow/io.kestra.plugin.core.flow.parallel) as it runs tasks in parallel.
:::
Expand Down
Loading
Loading