FluxCD 2.0 vs ArgoCD 2.7, A Real Comparison After Running Both in Production
TL;DR — ArgoCD 2.7 has the better UI and the better RBAC story; pick it for orgs that need self-service for many stream teams. / FluxCD 2.0 is more composable and CRD-native; pick it for platform teams that prefer kubectl-and-YAML over a portal. / Both are production-ready — the wrong reasons to choose are “it’s what we already know” and “the demo looked cooler.”
I’ve shipped both, and I keep being asked the same question: “Which one should we use?” The honest answer is that the technical differences are smaller than people think and the cultural differences inside your team matter more. Below is the comparison I actually use when consulting, broken down by the axes that have caused me real pain or real relief.
This builds on the previous posts in the series. The multi-tenancy substrate for either tool lives in Kubernetes 1.27 multi-tenancy patterns, and the ApplicationSet patterns I lean on with ArgoCD are in ApplicationSets at scale.
The architectural difference that actually matters
ArgoCD is a single application with multiple components (server, repo-server, application controller, dex, redis). It has a UI, a CLI, and an API. State lives in CRDs but the system feels like an app.
Flux is a set of controllers (source-controller, kustomize-controller, helm-controller, notification-controller, image-automation-controller). There’s no built-in UI. Each controller is independently versioned and independently usable. The system feels like Kubernetes.
This single design decision drives almost every other difference. ArgoCD optimizes for the user-facing experience; Flux optimizes for composability with the Kubernetes API.
Side-by-side: the YAML that does the work
Same task: continuously deploy a Helm chart from a Git repo into a namespace.
ArgoCD 2.7:
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: checkout
namespace: argocd
spec:
project: checkout
source:
repoURL: https://github.com/acme/deploy.git
targetRevision: main
path: apps/checkout/overlays/prod-us
destination:
server: https://kubernetes.default.svc
namespace: checkout
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- ServerSideApply=true
- CreateNamespace=true
FluxCD 2.0:
apiVersion: source.toolkit.fluxcd.io/v1
kind: GitRepository
metadata:
name: deploy
namespace: flux-system
spec:
interval: 1m
url: https://github.com/acme/deploy.git
ref:
branch: main
---
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: checkout
namespace: flux-system
spec:
interval: 5m
path: ./apps/checkout/overlays/prod-us
prune: true
sourceRef:
kind: GitRepository
name: deploy
targetNamespace: checkout
patches:
- target:
kind: Deployment
patch: |
- op: add
path: /spec/template/metadata/annotations/checksum.from.git
value: "auto"
ArgoCD is more concise for the simple case. Flux’s two-resource model (source + reconciler) wins when you have multiple things reading from the same source — image automation, Helm releases, raw Kustomizations — because the fetch happens once.
Scale and resource consumption
In a 200-application cluster, ArgoCD’s application-controller becomes the bottleneck. ArgoCD 2.7 added sharding for the application controller — ARGOCD_CONTROLLER_REPLICAS plus the shard distribution — which helps, but you still feel it. The repo-server’s git clone and Helm template work is the other hotspot; running multiple replicas helps for parallelism.
Flux scales more linearly because each controller does less and you can run each at its own replica count. A 200-app Flux setup typically uses fewer total resources, but it’s harder to reason about because you’re watching five controllers’ metrics instead of one app’s.
For a single cluster with a few hundred apps, either tool is fine. For dozens of clusters, the architecture difference shifts. ArgoCD with ApplicationSet and the cluster generator runs from a central control cluster managing many remote clusters — one ArgoCD, many destinations. Flux is pull-based per cluster: each cluster runs its own Flux and reconciles itself from Git. This is a substantively different operational model.
The pull-model wins on blast radius. Lose the central cluster in the ArgoCD model and you’ve lost the ability to deploy. Lose a cluster in the Flux model and the others keep going.
RBAC and multi-tenancy
ArgoCD’s AppProject plus the SSO-backed RBAC policy file is the most polished multi-tenant story in GitOps today. You can carve up “team X can sync apps in project Y, read-only on project Z” without writing custom controllers. The UI respects these boundaries.
Flux multi-tenancy is more primitive. The recommended pattern is “one Flux installation per tenant” or “one Flux installation with --default-service-account and impersonation per Kustomization.” The Flux docs at fluxcd.io document the pattern in detail. It works, but it’s YAML, not a portal — there’s no equivalent of the ArgoCD UI showing “what can this team see and do.”
If your stream teams will interact with the GitOps tool directly, ArgoCD wins. If only the platform team touches it (stream teams just push to Git), Flux is fine.
Image automation
Flux’s image-automation-controller is genuinely good. It scans a registry on an interval, finds new tags matching a policy, and opens a commit to your deploy repo updating the tag. ArgoCD does not ship this out of the box — you use Argo CD Image Updater as a separate component, and the integration is more brittle.
apiVersion: image.toolkit.fluxcd.io/v1beta2
kind: ImagePolicy
metadata:
name: checkout
namespace: flux-system
spec:
imageRepositoryRef:
name: checkout
policy:
semver:
range: '>=1.0.0 <2.0.0'
---
apiVersion: image.toolkit.fluxcd.io/v1beta1
kind: ImageUpdateAutomation
metadata:
name: deploy-auto
namespace: flux-system
spec:
interval: 5m
sourceRef:
kind: GitRepository
name: deploy
git:
checkout:
ref:
branch: main
commit:
author:
name: fluxbot
email: flux@acme.io
messageTemplate: 'chore: bump {{ range .Updated.Images }}{{ .Name }}={{ .NewTag }}{{ end }}'
push:
branch: main
update:
path: ./apps
strategy: Setters
I run this happily for non-prod environments. For prod, image promotion should be a deliberate PR, not an automation — but the same machinery works behind a manual approval gate.
Operator ergonomics
The day-to-day shape of using each tool is genuinely different.
ArgoCD: I open the UI. I see app health, sync status, the diff. I click “sync” or “refresh.” For a stream-team engineer who deploys once a week, this is the right interface.
Flux: I run flux get kustomizations -A, flux logs --follow, kubectl describe kustomization. The CLI is excellent and the Kubernetes events are descriptive. For a platform engineer who lives in a terminal, this is faster.
There’s a weave-gitops UI for Flux which works, but it’s a separate install and a separate product surface. Treat it as optional.
What FluxCD 2.0 actually changed
The 2.0 release (GA in mid-2023) is largely about API stability. The source.toolkit.fluxcd.io/v1 and kustomize.toolkit.fluxcd.io/v1 APIs went GA, the bootstrap UX improved, and the controllers got performance work. If you’re on 0.41, the upgrade is straightforward; if you’re starting fresh, start on 2.x directly.
The Helm controller’s OCI support is the underrated change. You can pull Helm charts from an OCI registry as a first-class source, which simplifies the chart distribution story considerably.
How I actually choose
After all the above, here’s the heuristic I use:
- Many stream teams, weekly deploys, prefer-a-portal culture → ArgoCD.
- One platform team owning everything, prefer-a-CLI culture → Flux.
- Dozens of clusters with strong blast-radius concerns → Flux (pull model).
- Single big cluster, many tenants → ArgoCD (better RBAC).
- Image automation is a must-have day-one → Flux.
- You already run Argo Workflows or Argo Rollouts → ArgoCD (single ecosystem).
Don’t choose based on “the community is bigger.” Both have substantial CNCF-graduate communities. Don’t choose based on “we tried it three years ago” — both products have changed materially since.
Common Pitfalls
- Running both. I’ve seen orgs where one team uses Flux and another uses ArgoCD on the same cluster. They fight over namespaces, RBAC, and admission. Pick one per cluster.
- Skipping the dry-run in CI. Both tools support
argocd app diffandflux diff kustomizationin CI on PR. Use it. The number of “this won’t change anything, promise” PRs that turn out to delete a Deployment is non-trivial. - Treating Helm hooks as first-class. Both tools’ Helm support has rough edges around hooks, especially
pre-installandpost-delete. Convert Helm hooks to native Kubernetes Jobs in your manifests when possible. - Letting Flux’s
decryption.provider: sopslapse on key rotation. SOPS-encrypted secrets in Git plus Flux is a great pattern, but rotate the KMS key on a schedule and test the rotation. Discovering your CI can no longer decrypt during an outage is bad. - Forgetting the
serviceAccountNameimpersonation in Flux multi-tenancy. Without it, a Flux Kustomization runs with the controller’s permissions — which are cluster-admin in default installs. That’s a multi-tenancy hole the size of a truck. - ArgoCD sync waves used as a workflow engine. They’re not. If you have ordering dependencies that need branching or retries, use Argo Workflows or Tekton, not sync waves.
Wrapping Up
The tools converged more than they diverged in 2023. Both are good. The decision is mostly about your team’s preferred interaction model and your operational topology. Pick the one whose failure modes you’d rather debug at 2am.
Next post: progressive delivery on top of whichever GitOps tool you chose. Canary deploys, automated rollback, and why “deploy to prod” should never mean “send all traffic to new version.”