Argo CD vs Flux: Choosing a GitOps Controller
Argo CD and Flux are the two serious choices for a GitOps controller on Kubernetes. Both are CNCF Graduated, both do pull-based reconciliation with drift detection and health checks, and both are excellent. The decision isn't about which one is "better" — it's about whether your platform wants an application-centric service with a dashboard, or a set of composable Kubernetes-native controllers you drive from CRDs and a CLI.
What they have in common
Strip away the branding and the core loop is identical. A controller runs inside (or beside) your cluster, watches one or more Git repositories, renders manifests, and continuously reconciles the live cluster state against the desired state in Git. If someone hand-edits a Deployment with kubectl, both tools detect the drift and either flag it or revert it, depending on configuration. Both assess resource health, both support Kustomize and Helm, both support multi-cluster setups, and both have mature notification systems. Neither pushes from CI — your pipeline builds an image and updates a manifest in Git, and the controller pulls the change. That shared foundation is why teams rarely regret either choice; they regret picking the one whose operating model fights their org.
Argo CD: an application platform with a UI
Argo CD runs as a standalone service — API server, repo server, application controller — and models everything around a single CRD: the Application. An Application binds a source (Git repo, path, revision, or a Helm chart) to a destination (cluster and namespace):
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: payments-api
namespace: argocd
spec:
project: payments
source:
repoURL: https://github.com/acme/deploy-manifests
targetRevision: main
path: apps/payments-api/overlays/prod
destination:
server: https://kubernetes.default.svc
namespace: payments
syncPolicy:
automated:
prune: true
selfHeal: trueThe headline feature is the web UI. It renders the full resource tree of every Application — Deployments, ReplicaSets, Pods, Services — with live health, sync status, diffs against Git, and one-click sync or rollback. For organizations where dozens of product teams deploy to shared clusters, this matters more than architecture diagrams suggest: developers can see why their rollout is stuck without learning kubectl, and platform teams answer far fewer "is it deployed yet" questions.
Multi-tenancy is first-class. AppProject resources scope which repos, clusters, and resource kinds a team may touch, and Argo CD's own RBAC layers on top with SSO (OIDC, SAML) integration. The app-of-apps pattern — an Application whose manifests are themselves Applications — bootstraps entire environments from one root, andApplicationSet generates Applications from generators: one per cluster, one per Git directory, one per open pull request. If you manage many clusters or many near-identical apps, ApplicationSet is the tool that keeps the repo from becoming copy-paste sprawl.
Flux: composable controllers, no service in front
Flux v2 takes the opposite shape. There is no central application service and no built-in UI. Instead you get the GitOps Toolkit: small, single-purpose controllers that compose through CRDs — source-controller (fetches Git repos, Helm repos, OCI artifacts, S3 buckets), kustomize-controller (builds and applies Kustomize overlays), helm-controller (manages HelmRelease lifecycles), andnotification-controller (events in and out). Everything is plain Kubernetes API objects:
apiVersion: source.toolkit.fluxcd.io/v1
kind: GitRepository
metadata:
name: deploy-manifests
namespace: flux-system
spec:
interval: 1m
url: https://github.com/acme/deploy-manifests
ref:
branch: main
---
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: payments-api
namespace: flux-system
spec:
interval: 10m
sourceRef:
kind: GitRepository
name: deploy-manifests
path: ./apps/payments-api/overlays/prod
prune: true
wait: trueYou operate it with the flux CLI (flux bootstrap,flux get kustomizations, flux reconcile) and observe it the same way you observe anything else in the cluster: kubectl get, events, Prometheus metrics. Because Kustomizations can depend on each other (dependsOn) and target different namespaces with different service accounts, multi-tenancy falls out of standard Kubernetes RBAC rather than a separate permission system — each tenant's Kustomization applies with a scoped ServiceAccount, and impersonation enforces the boundary.
The trade-off is visibility. Out of the box there is no dashboard; you add Weave GitOps or Capacitor if you want one, or lean on Grafana. Teams comfortable living in the CLI and CRDs often prefer this — one less stateful service to run, secure, and upgrade — but if your developers expect a self-service console, you're assembling it yourself.
Secrets: the one concrete feature gap
Neither tool wants plaintext secrets in Git, and both pair cleanly with Sealed Secrets or External Secrets Operator. The real differentiator is SOPS: Flux's kustomize-controller decrypts SOPS-encrypted files natively — point a Kustomization at a decryption key (age, GPG, or a cloud KMS) and encrypted YAML in Git just works. Argo CD has no built-in SOPS support; you bolt it on with plugins or sidecar hacks, all of which feel like exactly that. If SOPS is already your secrets workflow, that alone can settle the decision.
Side by side
| Dimension | Argo CD | Flux v2 |
|---|---|---|
| Architecture | Standalone service (API server, repo server, app controller) | Composable controllers (GitOps Toolkit), pure CRDs |
| UI/UX | Rich built-in web UI: resource tree, diffs, sync, rollback | No built-in UI; CLI-first, add Weave GitOps or Capacitor |
| App model | Application CRD, app-of-apps, ApplicationSet generators | GitRepository + Kustomization / HelmRelease, dependsOn chains |
| Multi-tenancy | AppProjects + own RBAC + SSO (OIDC/SAML) | Native Kubernetes RBAC + ServiceAccount impersonation |
| Secrets | Sealed Secrets / External Secrets; SOPS via plugins only | Same, plus native SOPS decryption in kustomize-controller |
| Notifications | Notifications engine (triggers + templates, many providers) | notification-controller (Alerts/Providers, inbound webhooks) |
| Learning curve | Gentler for app teams — the UI does the teaching | Gentler for Kubernetes-native operators; steeper for dev self-service |
Day-2 realities
Whichever you pick, budget for the operational surface. Argo CD is itself an application: it has its own upgrades, its own Redis, its own RBAC policy file, and — because the UI can sync and roll back workloads — its own attack surface that needs SSO wired correctly and admin accounts locked down on day one. It scales well, but large installations end up tuning repo server replicas and reconciliation timeouts. Flux's footprint is smaller and upgrades ride the same GitOps flow as everything else, but debugging shifts from "look at the dashboard" to reading controller logs and Kustomization status conditions, so invest early in dashboards and alerts for reconciliation failures — a Kustomization that silently stops applying is the failure mode nobody notices until an incident.
Notifications deserve the same treatment on both sides. Argo CD's notifications engine and Flux's notification-controller can both push sync results to Slack, Teams, or Git commit statuses, and both accept inbound webhooks so a Git push triggers reconciliation immediately instead of waiting for the polling interval. Teams that skip this end up with the worst of both worlds: pull-based delivery with push-based expectations.
How to actually choose
Ignore feature checklists and ask who operates this thing and who consumes it.
- Pick Argo CD when many product teams share clusters and you want a self-service application model: developers get a dashboard, per-team AppProjects, SSO, and visual rollbacks without touching kubectl. It's also the pragmatic default when adoption depends on people who will judge the platform by its UI.
- Pick Flux when a platform team owns delivery end-to-end and wants the controller to disappear into Kubernetes: minimal footprint, everything is a CRD, native SOPS, tight Kustomize and Helm integration, and tenancy enforced by the same RBAC you already audit. It composes well as the engine underneath your own platform tooling.
- Don't over-index on multi-cluster. Both handle it — ApplicationSet generators on one side, per-cluster bootstrap with shared repos on the other. Your repo structure matters more than the controller.
- Don't run both to hedge. Two reconciliation engines with overlapping scope is how you get fights over ownership of resources and 2 a.m. drift mysteries.
Rule of thumb: Argo CD is a product your teams use; Flux is a library your platform is built from. Choose the one that matches how your organization wants to work, then invest in repo structure, environments, and promotion flow — that's where GitOps efforts actually succeed or fail.
If you're weighing this decision for a real platform — existing clusters, tenancy requirements, a secrets story already in flight — we help teams make the call and land it in production as part of our GitOps consulting work, usually alongside broader Kubernetes platform engagements. The controller is the easy part; the repo layout, RBAC model, and promotion pipeline around it are where experience pays off.
Need this done, not just read about?
Deplyra builds, ships and runs exactly this in production — as code, with GitOps, handed over documented.
Start a project →