Argo Workflows v4.1.0 - Controller Memory And CRD Install


Argo Workflows v4.1.0 landed on 11 August 2026 as a stable minor, not a prerelease. The GitHub notes are an install stub; the changelog is where the work sits. For operators running ETL graphs on Kubernetes, the first change that matters is controller memory: informer caches now drop managedFields before storing objects, which the upgrading guide puts at roughly 20 percent of cached object size at scale.

The full release notes and downloads are on the GitHub release page. That page also points at the project blog and the issue tracker.

The only selected change on the v4.1.0 tag itself, relative to v4.1.0-rc2, is a new argo-workflows-crdinstaller image. It ships with each release, bundles kubectl plus the full CRDs for that tag, and applies them with server side apply by default. The intended caller is install tooling that cannot server side apply the full CRDs on its own, including community Helm charts.

Full CRDs are what you want for Validating Admission Policy and for kubectl explain on Argo types. Minimal CRDs keep working, but they do not carry the validation payload. The installer image is the air gapped path: no fetch from GitHub at apply time, CRDs baked into the image that matches the controller you are installing.

The classic cluster install is unchanged. The GitHub release page still documents kubectl apply -n argo -f against install.yaml for this tag. CLI binaries for Mac and Linux remain gzip payloads named argo-$ARGO_OS-amd64.gz.

workflow-controller, and the parts of argo-server that share its informers, strip metadata.managedFields before the object lands in the informer cache. Cluster objects are not rewritten. Nothing in the controller reads those fields. At scale, informer objects dominate controller RSS, so this is a cache tax cut.

Failed archive attempts are retried, and a workflow is archived once rather than being written again. Workflows that are already Running are no longer postponed. A DeepCopy of the full Workflow object is skipped for postponed workflows. ConfigMap watchers are gone; informers replace them. namespaceParallelism now hot reloads from the controller ConfigMap the same way parallelism already did, so a default change does not need a controller restart for namespaces that do not override it with a label.

INFORMER_WRITE_BACK is gone. It used to choose between writing the workflow update back into the informer cache (true) and sleeping one second (false, the old default). Other paths now stop reprocessing, so both behaviors are dead weight. If the variable is still on the Deployment, drop it.

Executor env parsing moved to the argoexec composition root and is enforced with forbidigo. That is an internal refactor. It does not change template YAML.

Artifact drivers gained SaveStream. Azure and HTTP/Artifactory can write an io.Reader straight to the destination. S3, GCS, OSS, and HDFS still buffer to a temp file and reuse the existing save path. Artifact plugins can advertise a client streaming SaveStream gRPC method; plugins that skip it keep the old Save path after a temp file buffer.

S3 upload parallelism is no longer a buried MinIO default. ARTIFACT_S3_UPLOAD_THREADS and ARTIFACT_S3_UPLOAD_PART_SIZE_MIB set thread count and part size. The prior default was 4 threads and a dynamic part size, commonly 16MiB below about 156GiB. addressingStyle on the S3 bucket config accepts empty (auto), path, or virtual-hosted. That last value is the fix for log streaming and artifact browsing against S3 compatible stores that only speak virtual hosted addressing.

Large node status blobs can use zstd or brotli instead of gzip. WORKFLOW_COMPRESSION_ALGORITHM selects the writer; WORKFLOW_COMPRESSION_LEVEL sets the level; readers detect the algorithm on the way back.

Workflow pods can declare resourceClaims at spec or template scope, forwarding Dynamic Resource Allocation claims instead of stuffing the whole list into podSpecPatch. Argo does not allocate devices. The cluster needs the DynamicResourceAllocation feature gate and a DRA driver. podResources sets a pod level CPU and memory budget shared by main, init, wait, and sidecars. That field needs the PodLevelResources gate (beta and on by default since Kubernetes v1.34). If the gate is off, the API server strips the field and the controller emits PodLevelResourcesDropped.

pendingTimeout on a template caps how long a pod may sit Pending before the controller marks the node Failed and deletes the pod. Persistence can take AWS RDS PostgreSQL IAM tokens and Azure PostgreSQL Entra ID tokens, which removes long lived database passwords from the archive and sync stores.

Read the upgrading guide before you roll the controller. The v4.1 section is short.

argo archive get, delete, resubmit, and retry now take a workflow name or a UID. A UUID shaped argument is still a UID; anything else is a name in the selected namespace. Duplicate names fail the command and print the matching UIDs. --uid and --name force the parse when a workflow name itself looks like a UUID. Scripts that already pass UIDs keep working.

initlessPod.enabled: true in the controller ConfigMap is a beta layout that drops the argoexec init container. Leave it off unless you have a reason; in flight pods keep the layout they were scheduled with.

v4.1.0 is the minor cut after v4.1.0-rc1 and v4.1.0-rc2. Search existing issues on GitHub as the release notes ask.