Argo Workflows’ withItems is a powerful way to iterate over lists, but it’s not just about running the same template multiple times; it’s fundamentally about data transformation at scale.
Let’s see it in action. Imagine you have a list of server names and you want to check the health of each one.
apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
generateName: withitems-example-
spec:
entrypoint: health-check
templates:
- name: health-check
inputs:
parameters:
- name: server
container:
image: alpine:latest
command: ["sh", "-c"]
args:
- echo "Checking health of server: {{inputs.parameters.server}}"; sleep 2
- name: main
dag:
tasks:
- name: check-all-servers
template: health-check
withItems:
- server-01.example.com
- server-02.example.com
- server-03.example.com
When this workflow runs, Argo doesn’t just clone the health-check template three times. It creates three distinct instantiations of the health-check template, each with a unique server input parameter derived from the withItems list. The {{inputs.parameters.server}} placeholder within the template gets replaced with server-01.example.com, then server-02.example.com, and finally server-03.example.com for each corresponding task. This allows for parameterized execution based on the list’s contents.
The core problem withItems solves is running a set of operations where the input data for each operation varies. Think about processing files in a directory, querying multiple databases, or making API calls to a list of endpoints. Without withItems, you’d either manually create a separate task for each item (unmanageable for large lists) or write complex scripting within a single container (harder to monitor and manage). withItems provides a declarative and scalable way to handle this pattern.
Internally, Argo Workflows translates the withItems directive into a series of independent workflow steps or DAG tasks. For each element in the withItems list, a new task is generated. This task inherits the template specified and receives the corresponding list item as an input parameter. The system then schedules and executes these generated tasks independently, allowing for parallelism if your cluster and workflow configuration permit. You can control the degree of parallelism by setting resource limits or using Argo’s concurrency control mechanisms.
The withItems field can accept a list of strings, numbers, booleans, or even complex JSON objects. When using complex objects, you access their fields within the template using dot notation or get functions. For instance, if your withItems was [{ "host": "db1", "port": 5432 }, { "host": "db2", "port": 5432 }], you could reference {{inputs.parameters.host}} and {{inputs.parameters.port}} within your template. This makes withItems incredibly flexible for structured data iteration.
A common point of confusion is how withItems interacts with other input parameters. If a template used by withItems also declares input parameters that are not part of the withItems list, those parameters will be shared across all iterations. This is useful for passing down common configuration, like a database connection string or an API key, to every task generated by withItems. The system ensures that these shared parameters are available to each instantiated task, maintaining a consistent context for each item’s processing.
When you use withItems, Argo Workflows creates multiple task pods. If one of these pods fails, it doesn’t necessarily fail the entire withItems expansion. The overall workflow status will reflect the individual task statuses, and you can configure retry strategies at the task level to handle transient failures for specific items.
The next logical step after iterating over simple lists is to explore dynamic list generation using withParam or withExpr to fetch data from external sources or compute lists on the fly.