Sitemap

GitOps in Practice: Argo CD vs. Flux (A Real Workflow and the Pitfalls Nobody Warns You About)

6 min readSep 26, 2026

--

Stop running kubectl apply by hand. Here's how two CNCF-graduated tools make Git the single source of truth for your cluster, and how to choose between them.

The 2 AM problem

It’s 2 AM. Production is misbehaving. Someone ran a quick kubectl edit deployment last week to "temporarily" bump the memory limit. Nobody wrote it down, and nobody remembers. Now your Git repo says one thing, your cluster says another, and you're debugging a system that no longer matches its own documentation.

This is configuration drift, and it’s the exact problem GitOps was built to kill.

In this post I’ll cover:

  • What GitOps really is (without the buzzwords)
  • How Argo CD and Flux differ in philosophy and architecture
  • A real end-to-end workflow you can copy
  • The pitfalls that trip up almost every team
  • A simple guide for choosing between them

What is GitOps, really?

GitOps is an operating model built on four ideas:

  1. Declarative: you describe the desired state of your system (Kubernetes YAML, Helm charts, Kustomize overlays).
  2. Versioned: that desired state lives in Git, so every change has an author, a diff, and a history.
  3. Pulled automatically: an agent inside the cluster pulls the desired state from Git, instead of your CI pipeline pushing to the cluster.
  4. Continuously reconciled: the agent constantly compares the live state to Git and corrects any drift.

The pull model is the big shift. In traditional CI/CD, your pipeline holds cluster credentials and pushes changes in. With GitOps, the cluster reaches out to Git. Your CI system never needs admin access to production, which is a big security win.

Git is the source of truth. The cluster is just a reflection of it.

Meet the contenders

Both tools are CNCF graduated projects, so both are mature and production-proven. They solve the same core problem in quite different ways.

Argo CD: the visual powerhouse

Argo CD is built around the concept of an Application: a link between a Git path and a destination cluster and namespace. Its standout feature is a polished web UI that shows your resources as a live graph, with health and sync status at a glance.

Key traits:

  • Rich UI and CLI, plus built-in SSO/RBAC
  • Manages multiple clusters from one control plane
  • ApplicationSets for generating apps at scale
  • Easy to demo, easy for teams to adopt quickly

Flux: the Kubernetes-native toolkit

Flux is built as a set of small, focused controllers (the GitOps Toolkit) that follow Kubernetes conventions. There’s no big central app. Everything is a Custom Resource, so Flux feels like a natural extension of Kubernetes itself.

Key traits:

  • Modular controllers: source, kustomize, helm, notification, and image automation
  • CLI-first and lightweight, with no built-in UI
  • Strong support for image automation (auto-updating tags in Git)
  • Excellent for platform teams who want everything as code

A real workflow: from commit to cluster

Let’s build a realistic setup. First, a repository structure that scales:

gitops-repo/
├── apps/
│ ├── base/
│ │ └── web-app/
│ │ ├── deployment.yaml
│ │ ├── service.yaml
│ │ └── kustomization.yaml
│ └── overlays/
│ ├── staging/
│ │ └── kustomization.yaml
│ └── production/
│ └── kustomization.yaml
└── clusters/
├── staging/
└── production/

The pattern is base + overlays. Shared config lives in base, and environment-specific differences (replicas, resource limits, hostnames) live in the overlays.

The end-to-end flow

  1. A developer opens a pull request with a code change.
  2. CI runs tests, builds the container image, and pushes it to a registry.
  3. CI (or an automation tool) updates the image tag in the GitOps repo via a PR.
  4. The PR is reviewed and merged, and that review is your change-approval process.
  5. Argo CD or Flux detects the new commit and reconciles the cluster.
  6. If anyone changes the cluster manually, the tool reverts it back to Git.

Notice that CI never touches the cluster. It only writes to Git.

Setting it up with Argo CD

Install it, then define an Application:

yaml

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: web-app
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/your-org/gitops-repo
targetRevision: main
path: apps/overlays/production
destination:
server: https://kubernetes.default.svc
namespace: web-app
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true

The two flags that matter most:

  • selfHeal: true reverts manual changes made in the cluster.
  • prune: true deletes resources that you've removed from Git.

Setting it up with Flux

Bootstrap Flux into your cluster and point it at your repo:

Get Mohammedyasik R Applogiq’s stories in your inbox

Join Medium for free to get updates from this writer.

bash

flux bootstrap github \
--owner=your-org \
--repository=gitops-repo \
--branch=main \
--path=clusters/production \
--personal

Then define a source and a Kustomization:

yaml

apiVersion: source.toolkit.fluxcd.io/v1
kind: GitRepository
metadata:
name: gitops-repo
namespace: flux-system
spec:
interval: 1m
url: https://github.com/your-org/gitops-repo
ref:
branch: main
---
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: web-app
namespace: flux-system
spec:
interval: 5m
path: ./apps/overlays/production
prune: true
sourceRef:
kind: GitRepository
name: gitops-repo

Flux also manages itself from Git during bootstrap, so even the GitOps tool is version-controlled.

Argo CD vs. Flux: the honest comparison

User interface

  • Argo CD: excellent built-in UI, great for visibility and onboarding.
  • Flux: no official UI. You work through the CLI, kubectl, and dashboards like Grafana.

Architecture

  • Argo CD: a more centralized application with its own API server, repo server, and controller.
  • Flux: a set of independent Kubernetes-native controllers.

Multi-cluster

  • Argo CD: one instance can manage many clusters, which is convenient but makes it a critical central point.
  • Flux: typically runs in each cluster, which is more decentralized.

Access control

  • Argo CD: built-in RBAC and SSO integration.
  • Flux: leans on native Kubernetes RBAC and multi-tenancy patterns.

Image automation

  • Flux: built-in image reflector and automation controllers.
  • Argo CD: handled by the separate Argo CD Image Updater project.

Learning curve

  • Argo CD: easier to get started, thanks to the UI.
  • Flux: steeper at first, but very consistent once you know Kubernetes CRDs.

The pitfalls (learn from other people’s pain)

1. Putting secrets in Git in plain text

GitOps says “everything in Git,” but that does not include raw secrets. Use Sealed Secrets, SOPS, or the External Secrets Operator with Vault or a cloud secret manager. Decide this on day one, not after your first leak.

2. One giant repository for everything

Dumping every app, environment, and team into one repo leads to noisy history and permission headaches. Separate app code from deployment config, and consider splitting by team or environment as you grow.

3. Fighting the autoscaler

If your Deployment has replicas: 3 in Git and the HPA scales it to 8, the GitOps tool may keep "fixing" it back to 3. Remove the replicas field from the manifest, or configure the tool to ignore that field.

4. Turning on prune without understanding it

Auto-pruning is powerful. A bad merge or a mistaken path change can delete real resources, including things like PersistentVolumeClaims. Test it in staging first and protect critical resources.

5. Treating Git merges as instant deploys

Reconciliation isn’t instant. Flux polls on an interval, and Argo CD polls Git periodically. If you need speed, configure webhooks so Git pushes trigger a sync right away.

6. Skipping progressive delivery

GitOps tells you what to deploy, not how safely. For canary and blue-green rollouts, pair it with Argo Rollouts or Flagger.

7. Ignoring drift alerts

A sync failure that nobody sees is worse than no GitOps at all. Wire up notifications (Slack, Teams, email) so failed reconciliations are loud.

8. Bootstrapping order problems

CRDs must exist before the resources that use them. Use dependency ordering (dependsOn in Flux, sync waves in Argo CD) to avoid mysterious failures on fresh clusters.

So which one should you choose?

Choose Argo CD if:

  • You want a rich UI and quick team adoption
  • You manage many clusters from one place
  • You need built-in SSO and fine-grained RBAC
  • Your teams include people who are less comfortable with the CLI

Choose Flux if:

  • You prefer a lightweight, modular, Kubernetes-native approach
  • You’re a platform team building on top of GitOps
  • You want built-in image update automation
  • You favor a decentralized, per-cluster model

And remember: plenty of successful companies use one or the other, and some use both. The tool matters much less than the discipline: everything in Git, reviewed by humans, reconciled by machines.

Final thoughts

GitOps isn’t about picking the trendiest tool. It’s about making deployments boring, auditable, and reversible. When something breaks, you don’t SSH into servers or guess what changed. You look at the Git history and run git revert.

Whether you go with Argo CD’s dashboard or Flux’s composable controllers, you’ll be trading late-night firefighting for calm, predictable releases.

Pick one, start small with a single non-critical app, and let Git be your source of truth. Your future self at 2 AM will thank you.

--

--