GitOps: Argo CD & Flux
Teams need a clear delivery model before GitOps becomes another layer of operational confusion
Delivery as explicit platform contracts
Andrey Lesnikov · Senior DevOps Platform Engineer · 2026-10-22 · sources checked 2026-10-22
Part of Kubernetes GitOps architecture
"Argo CD vs Flux" is still the default shortlist when a platform team picks a GitOps engine. Both watch Git (and related sources), both reconcile cluster state, both are CNCF projects. The useful differences are the object model, how often they reconcile, how they heal drift, and what you operate day to day.
This guide is grounded in two kinds of source. First, the public gitops-duel-argocd-vs-flux repository: Terraform modules that install both tools, sample apps, Kind CI, and committed timings in docs/results.md / docs/EVIDENCE.md. Second, the current Argo CD and Flux documentation for sync policy, reconciliation timeouts and HelmRelease behaviour. The duel numbers are single-node kind lab timings for sample Helm nginx apps, not multi-cluster production sync SLOs — the repo states that limit explicitly.
Argo CD centres on the Application custom resource. An Application points at a Git path (plain manifests, Kustomize, Helm, or other config-management plugins), a destination cluster/namespace, and a sync policy. The application controller compares desired manifests to live objects and can sync, prune and self-heal. Automated sync is documented in the Argo CD user guide: enable spec.syncPolicy.automated, optionally with prune and selfHeal.
Flux is a set of controllers with separate CRDs. Common pieces for app delivery are GitRepository (or other sources), Kustomization and HelmRelease. Each object carries its own spec.interval. Flux reconciles when the interval elapses (and on events the controllers observe); there is no single Application UI object that owns the whole tree unless you build that with your own conventions.
Neither description is a ranking. They are different packaging of the same GitOps idea: desired state in Git, continuous reconcile in the cluster.
In gitops-duel-argocd-vs-flux (release tag checked: v1.0.1):
modules/argocd, modules/fluxcd).apps/argocd/ and apps/flux/..github/workflows/test-kind.yml) brings up Kind, applies the stack, runs sync / self-heal / deletion-recovery drills, and can publish benchmark artifacts.docs/EVIDENCE.md: Reference implementation).An Argo CD Application from the repo (abbreviated):
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: nginx-helm-app
namespace: argocd
spec:
destination:
namespace: default
server: https://kubernetes.default.svc
project: default
source:
repoURL: https://github.com/justrunme/gitops-duel-argocd-vs-flux.git
targetRevision: HEAD
path: charts/nginx
helm:
values: |
replicaCount: 2
image:
repository: nginx
tag: "1.25.2"
syncPolicy:
automated:
prune: true
selfHeal: true
A Flux HelmRelease from the same repo (abbreviated):
apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
name: helm-nginx
namespace: flux-system
spec:
interval: 1m
chart:
spec:
chart: nginx
version: "15.1.1"
sourceRef:
kind: HelmRepository
name: bitnami
namespace: flux-system
values:
service:
type: ClusterIP
Worth stating clearly: in these manifests Argo CD renders the in-repo charts/nginx path, while this Flux HelmRelease pulls a Bitnami chart via HelmRepository. The duel is "both tools delivering nginx-shaped apps under the same CI fault drills", not byte-identical chart packaging. The Flux module also creates a GitRepository with spec.interval: 10s for the equal-interval lab profile.
The Argo CD module sets timeout.reconciliation to 10s in ConfigMap for the equal-interval profile. That is a lab setting, not a recommendation for production.
Official Argo CD automated-sync docs: an Application with syncPolicy.automated syncs when it is OutOfSync. Self-heal re-syncs when live state drifts from Git. The controller's reconcile loop interval is governed by timeout.reconciliation in argocd-cm. The same docs page currently describes the default as 120s with added jitter (up to about three minutes). The duel repo's defaults profile records Argo stock as 180s in its methodology table — treat that as what that CI profile used as its "stock" stand-in, and confirm the value in your installed chart/version rather than copying either number blindly.
Official Flux docs: HelmRelease and Kustomization reconcile on spec.interval (and related source intervals). The duel results.md notes that the stock Flux Kustomization default is 10m, and that the CI defaults profile used 1m as a bounded stand-in. Shorter intervals mean faster convergence and more API load.
Practical difference:
| Concern | Argo CD (as documented / used in the duel) | Flux (as documented / used in the duel) |
|---|---|---|
| Primary unit | Application |
Source + Kustomization / HelmRelease |
| Drift repair | automated.selfHeal |
Controllers re-apply desired state on reconcile |
| Prune | automated.prune |
Depends on the object (prune on Kustomization, Helm uninstall semantics on HelmRelease) |
| Interval knob | timeout.reconciliation (and related controller flags) |
Per-object spec.interval |
| UI | Built-in Argo CD UI | No single product UI; kubectl, Weave GitOps, or your own |
docs/EVIDENCE.md maps claims to CI. Status vocabulary there: Tested in CI / Reference implementation / Simulated / Not yet. The benchmark claim is Tested in CI, with this limit quoted from the repo: single-node kind numbers are lab timings for sample Helm nginx apps — not multi-cluster production sync SLOs.
Committed profile equal-10s (both tools aimed at a 10s reconcile cadence), from docs/results.md, Demo results run 38131680035, measured_at 2026-10-11T11:00:03Z, n=3 medians:
| Tool | Time to Ready (s) | Self-heal (s) | Deletion recovery (s) | Commit→Ready (s) |
|---|---|---|---|---|
| Argo CD | 3.759 | 3.666 | 3.130 | 19.068 |
| Flux | 6.167 | 12.767 | 70.208 | 8.289 |
On the defaults profile in the same file (Argo reconciliation stand-in 180s; Flux interval stand-in 1m), medians include Argo CD commit→ready 312.054 s and Flux self-heal 65.157 s / deletion recovery 119.997 s. The repo says these values are taken verbatim from CI; no estimated timings are published.
How to read that without over-claiming:
equal-10s is still a lab sample on nginx, not a fleet SLO.docs/EVIDENCE.md.If you need the raw samples, use docs/results.json in the repo.
| You need | Lean towards |
|---|---|
| An Application-centric UI and a single object per delivery unit | Argo CD |
| Composable controllers (source, kustomize, helm, notification) and GitOps without a central app UI | Flux |
| App-of-apps / ApplicationSet-style fan-out as first-class docs and UX | Argo CD (see also Argo CD App of Apps) |
| Per-resource intervals and a toolkit model | Flux |
| Evidence from the same kind drills this guide cites | Run or read gitops-duel-argocd-vs-flux; do not import the seconds into contracts |
What neither comparison replaces: promotion policy between clusters, signed supply chain, progressive delivery, and human approval gates. Those sit beside the engine. The GitOps: Argo CD & Flux case and the Kubernetes GitOps hub collect how I use both tools in platform work.
Cases
Teams need a clear delivery model before GitOps becomes another layer of operational confusion
Delivery as explicit platform contracts
As platforms grow, application onboarding, add-ons, and environment drift become hard to reason about
Platform bootstrapable from Git
Multi-region systems need repeatable promotion and rollback without turning every deployment into manual coordination
Regional drift stays auditable