Originally published on kuryzhev.cloud
The scenario
A platform team runs Argo CD 3.2 or 3.3 in a shared cluster, with a few hundred Applications, and the ticket says "get to Argo CD 3.5 before the next audit". Argo CD 3.5 was released in August 2026 (see the official releases page), and the cycle has since collected patch releases up to 3.5.6. That matters now because the upstream support policy covers only the newest minor lines, and every month you wait widens the gap you have to cross.
Short answer: do not treat this as a version bump in a manifest. Back up the Argo CD state, read the upgrade notes for every minor between your version and 3.5, rehearse on a non-production instance with a pinned 3.5.x manifest, then promote and watch sync metrics. This applies if you are on any 3.x minor; if you are still on 2.x, this is a different, bigger migration.
One caveat up front: this article does not reproduce the 3.5 changelog line by line. The authoritative list of behavior changes lives in the upgrade pages of the Argo CD documentation (operator manual, "Upgrading" section) and the release notes. What follows is the process that turns that list into a safe rollout.
Prerequisites
Before touching anything, make sure you have the following in place:
- Sufficient Kubernetes permissions: admin rights in the namespace running Argo CD (assumed
argocdbelow), plus cluster-scoped permission to apply CRDs and cluster roles. - The argocd CLI at a version matching the server you are targeting. A CLI that is several minors behind can behave oddly against a newer API server.
- A non-production Argo CD with a representative slice of Applications, ApplicationSets and your real
argocd-cm/argocd-rbac-cmsettings. A vanilla install tells you little. - Your install method written down: raw upstream manifests (standard or HA), Kustomize overlay, or the community Helm chart. Each pins versions differently, and a chart version is not the same number as the app version.
- A Kubernetes compatibility check. If your clusters are moving to Kubernetes 1.37, confirm the tested-versions information in the Argo CD docs for your target release.
Watch out for exposure through ingress-nginx. That controller was retired in March 2026 and gets no further security fixes. If argocd-server sits behind it, plan the move to Gateway API or another maintained controller as a separate change. Do not do it in the same window as the Argo CD upgrade, because mixing the two makes any login or gRPC failure ambiguous.
Step 1: Snapshot the current state
You need two things to compare against later: a restorable backup of Argo CD's own configuration and a baseline of what every Application looks like today. The block below captures both.
# Record the running versions (client and server) argocd version # Backup Applications, AppProjects, settings and secrets handled by Argo CD argocd admin export -n argocd > argocd-backup-$(date +%F).yaml # Baseline: name, sync status, health for every app argocd app list -o json \ | jq -r '.[] | [.metadata.name, .status.sync.status, .status.health.status] | @tsv' \ | sort > baseline-apps.tsv wc -l baseline-apps.tsv # keep this count, you will compare it later Store the export somewhere encrypted, because it can contain repository credentials and cluster secrets. Also note any Applications that are already OutOfSync or Degraded. A typical failure during upgrades is blaming the new version for drift that existed beforehand.
Step 2: Read the notes for every minor and diff your config
Go to the operator manual's upgrading section and read each page between your current minor and 3.5, in order. For example, read 3.3 to 3.4, then 3.4 to 3.5. Upstream documents upgrades one minor at a time, and skipped notes are where defaults changed without you noticing.
While reading, sort each item into three buckets: breaking changes that need a config edit, changed defaults that alter runtime behavior, and deprecations with a removal date. Then check your own settings against them. Look specifically at argocd-cm (resource customizations, tracking method, exclusions), argocd-cmd-params-cm (component flags), argocd-rbac-cm (policies) and any config management plugins.
Watch out for resource tracking and ignore-difference settings. Changes in how Argo CD tracks or diffs resources are exactly the kind of thing that can flip hundreds of Applications to OutOfSync after an otherwise clean upgrade. If a note touches either, test it on the staging instance first with argocd app diff on several real Applications.
Also review your pinned dependencies. The Helm and Kustomize versions bundled in the repo-server image can change between minors, which can alter rendered output for the same chart. Run argocd admin settings --help to see the validation helpers your CLI version provides, and use them on your edited ConfigMaps.
Step 3: Rehearse on staging with a pinned manifest
Pin an exact patch version, never a moving tag like stable. The documented way to handle the large Argo CD CRDs without annotation-size errors is to apply the upstream install manifest with server-side apply. Use the manifest that matches your current topology: manifests/install.yaml for a standard install, manifests/ha/install.yaml for HA. Applying the non-HA manifest over an HA install replaces the HA components.
# Staging context first kubectl config use-context staging # Pin the patch release; v3.5.6 is the latest 3.5.x at time of writing # (HA installs: use manifests/ha/install.yaml instead) kubectl apply -n argocd --server-side --force-conflicts \ -f https://raw.githubusercontent.com/argoproj/argo-cd/v3.5.6/manifests/install.yaml # Wait for control plane components kubectl -n argocd rollout status deploy/argocd-server kubectl -n argocd rollout status deploy/argocd-repo-server kubectl -n argocd rollout status statefulset/argocd-application-controller If you use a Kustomize overlay or Helm chart, change the version there and render the diff first. For Kustomize, use kustomize build . | kubectl diff --server-side -f -. For Helm, use helm diff upgrade <release> <chart> --version <chart-version>, which requires the helm-diff plugin.
Gotcha: --force-conflicts makes the apply take ownership of every field the upstream manifest sets, even where another field manager changed it. Any hand edits to those fields will be reset unless they live in your overlay; this covers container args, images and env made with kubectl edit or kubectl patch. Fields the manifest does not set are left alone. Review the diff for that before applying.
Step 4: Promote to production and keep a way back
Repeat the same command against production during a quiet window, and avoid doing it while a big release is mid-sync. The application controller restarts and re-reconciles everything, so expect a burst of repo-server and API-server load; for large installs this is the real cost of the upgrade.
Your rollback plan is concrete. First, re-apply the previous pinned manifest. If state looks damaged, restore from the export with argocd admin import -n argocd - < argocd-backup-YYYY-MM-DD.yaml. Be aware that CRD schema changes are not always cleanly reversible, so the rehearsal on staging is what actually de-risks this, not the rollback.
When not to do this: do not upgrade in the middle of an incident, a freeze, or while you cannot get a human to watch the first reconciliation. If you manage many clusters from one Argo CD, also consider upgrading a secondary instance first. The extra instance costs money and operational overhead, but limits blast radius.
Verify and test
Start with versions and component health, then compare against the baseline you took in step 1.
argocd version # server should report v3.5.6 argocd app list -o json \ | jq -r '.[] | [.metadata.name, .status.sync.status, .status.health.status] | @tsv' \ | sort > after-apps.tsv diff baseline-apps.tsv after-apps.tsv && echo "no status drift" An empty diff means every Application kept its sync and health status. Any lines that differ are your investigation list. Run argocd app diff <name> on each to see whether the cause is rendering, tracking or a genuine change. Then test the full path with one throwaway Application: sync it, change a value in Git, and confirm that the change is detected and applied.
For ongoing confidence, watch the Prometheus metrics Argo CD exposes:
-
argocd_app_info, grouped bysync_statusandhealth_status, should return to its pre-upgrade shape within a few reconcile cycles. -
argocd_app_sync_total, filtered by itsphaselabel, should show failed or errored syncs increasing only when you expect them. - Pod restarts and repo-server logs are worth checking too. Repeated restarts after the first hour usually point to resource limits that need adjusting.
Closing
An Argo CD 3.5 upgrade from 3.x is mostly a reading and rehearsal exercise:
- Snapshot with
argocd admin export. - Work through each minor's upgrade notes.
- Pin
v3.5.6or later, using the manifest that matches your install topology. - Apply with server-side apply on staging.
- Compare application status before and after.
Keep the official documentation open while you do it, because defaults and flags are version-specific and anything in this article should be checked against it. For more runbooks on GitOps and platform tooling, browse kuryzhev.cloud.
