GitOps in 2026: ArgoCD vs Flux vs Helm — The Complete Comparison



GitOps in 2026: ArgoCD vs Flux vs Helm — The Complete Comparison

GitOps has won. The debate now isn’t “should we use GitOps” — it’s “which tool.” ArgoCD and Flux v2 are the two dominant Kubernetes-native GitOps platforms, each with distinct philosophies. This guide cuts through the marketing and tells you what actually matters.

DevOps Pipeline Photo by Roman Synkevych on Unsplash


What Is GitOps?

GitOps is a deployment model where:

  1. Desired state lives in Git (manifests, Helm charts, Kustomize configs)
  2. An operator runs in the cluster and continuously reconciles actual state to desired state
  3. All changes go through Git (PR → merge → auto-deploy)

Benefits:

  • Audit trail for every change (Git history)
  • Easy rollback (revert commit)
  • Drift detection (operator catches manual changes)
  • Developer-centric workflow (no kubectl in CI/CD)

ArgoCD

Architecture

ArgoCD runs as a set of components in your cluster and provides both a CLI and a beautiful web UI.

Git Repo (desired state)
        ↓
   ArgoCD Server
   ├── Application Controller (reconciliation loop)
   ├── Repo Server (manifest rendering)
   ├── API Server (CLI/UI/webhook interface)
   └── Dex (OIDC/SSO)
        ↓
  Kubernetes Cluster (actual state)

Core Concepts

Application: The fundamental unit — a Git source mapped to a Kubernetes destination.

# ArgoCD Application
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: my-app
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://github.com/myorg/my-app
    targetRevision: HEAD
    path: k8s/overlays/production
    # Or Helm:
    # chart: my-app
    # helm:
    #   values: |
    #     replicaCount: 3
    #     image.tag: "1.2.3"
  destination:
    server: https://kubernetes.default.svc
    namespace: my-app
  syncPolicy:
    automated:
      prune: true       # Delete resources removed from Git
      selfHeal: true    # Revert manual kubectl changes
    syncOptions:
      - CreateNamespace=true

ApplicationSet: Generate multiple Applications from a template:

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: cluster-addons
spec:
  generators:
  - list:
      elements:
      - cluster: production
        url: https://prod-cluster:6443
      - cluster: staging
        url: https://staging-cluster:6443
  template:
    metadata:
      name: '{{cluster}}-addons'
    spec:
      source:
        repoURL: https://github.com/myorg/cluster-addons
        path: '{{cluster}}'
      destination:
        server: '{{url}}'
        namespace: kube-system

ArgoCD Strengths

  1. UI is genuinely excellent: Real-time sync status, resource tree, diff view, pod logs — all in one place
  2. ApplicationSets: Powerful multi-cluster, multi-environment management
  3. RBAC: Fine-grained access control (who can sync what to where)
  4. Rollback UX: One click to rollback to any previous Git revision
  5. App-of-Apps pattern: Manage ArgoCD itself as an ArgoCD application
  6. Progressive delivery: First-class integration with Argo Rollouts

ArgoCD Weaknesses

  1. Heavier resource footprint: 4-6 pods by default, ~500MB RAM for a typical install
  2. Separate project from the main CNCF GitOps ecosystem (though widely adopted)
  3. CRD-heavy: Learning curve for operators new to it

Flux v2

Architecture

Flux follows the “single-responsibility” philosophy — separate controllers for each concern.

Git Repo / Helm Repo / OCI Registry
              ↓
        Source Controller
              ↓
   ┌──────────────────────┐
   │  Kustomize Controller │
   │  Helm Controller      │
   │  Notification Controller│
   │  Image Automation     │
   └──────────────────────┘
              ↓
        Kubernetes Cluster

Core Concepts

GitRepository: Defines a Git source

apiVersion: source.toolkit.fluxcd.io/v1
kind: GitRepository
metadata:
  name: my-app
  namespace: flux-system
spec:
  interval: 5m
  url: https://github.com/myorg/my-app
  ref:
    branch: main
  secretRef:
    name: github-credentials

Kustomization: Apply a path from a source

apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
  name: my-app
  namespace: flux-system
spec:
  interval: 10m
  path: ./k8s/production
  prune: true
  sourceRef:
    kind: GitRepository
    name: my-app
  healthChecks:
  - apiVersion: apps/v1
    kind: Deployment
    name: my-app
    namespace: my-app
  postBuild:
    substituteFrom:
    - kind: ConfigMap
      name: cluster-vars
    - kind: Secret
      name: cluster-secrets

HelmRelease: Deploy a Helm chart

apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
  name: nginx-ingress
  namespace: flux-system
spec:
  interval: 30m
  chart:
    spec:
      chart: ingress-nginx
      version: ">=4.0.0"
      sourceRef:
        kind: HelmRepository
        name: ingress-nginx
  values:
    controller:
      replicaCount: 2
  upgrade:
    remediation:
      retries: 3

Flux’s Image Automation

Flux’s image update automation is uniquely powerful:

# Watch for new image tags
apiVersion: image.toolkit.fluxcd.io/v1beta2
kind: ImageRepository
metadata:
  name: my-app
  namespace: flux-system
spec:
  image: ghcr.io/myorg/my-app
  interval: 5m

---
# Policy: use the latest semver patch release of 1.x
apiVersion: image.toolkit.fluxcd.io/v1beta2
kind: ImagePolicy
metadata:
  name: my-app
  namespace: flux-system
spec:
  imageRepositoryRef:
    name: my-app
  policy:
    semver:
      range: ">=1.0.0 <2.0.0"

---
# Automatically commit new image tags to Git
apiVersion: image.toolkit.fluxcd.io/v1beta1
kind: ImageUpdateAutomation
metadata:
  name: my-app
  namespace: flux-system
spec:
  interval: 30m
  sourceRef:
    kind: GitRepository
    name: my-app
  git:
    checkout:
      ref:
        branch: main
    commit:
      author:
        email: flux@myorg.com
        name: Flux
      messageTemplate: "chore: update images"
    push:
      branch: main

This means Flux can bump image tags in Git automatically — a full GitOps loop where even the image update is committed to Git.

Flux Strengths

  1. Lightweight: Modular controllers, lower resource usage
  2. OCI support: Store Flux manifests as OCI artifacts (not just Git)
  3. Multi-tenancy: Better isolation model for platform teams
  4. Image automation: First-class auto-update support
  5. Pure GitOps philosophy: Everything is a CRD, no separate UI state
  6. CNCF incubating project: Strong community governance

Flux Weaknesses

  1. No native UI: Requires separate tools (Weave GitOps, Capacitor)
  2. Steeper initial learning curve: The controller decomposition is powerful but more to understand
  3. Rollback is manual: You need to revert Git commits yourself

Feature Comparison

FeatureArgoCDFlux v2
Web UIExcellent (built-in)Requires add-on
CLIargocd CLIflux CLI
RBACFine-grained, built-inKubernetes RBAC
Multi-clusterApplicationSetMulti-tenancy model
Helm supportYesHelmRelease CRD
KustomizeYesYes (native)
OCI artifactsYes (2.6+)Yes (native)
Image automationArgo Image UpdaterBuilt-in
Progressive deliveryArgo RolloutsFlagger
NotificationsYesNotification Controller
Resource usage~500MB~150MB
CNCF statusGraduatedIncubating

Helm in This Picture

Helm is not a GitOps tool — it’s a package manager. But it’s central to both ArgoCD and Flux workflows.

# Helm alone (not GitOps): imperative
helm install my-release my-chart --values values.yaml

# GitOps with Helm: you declare the desired Helm release as a CRD
# and the operator applies/upgrades it automatically

Best practice: Use Helm charts for packaging your application, but manage the release through ArgoCD or Flux. Don’t run helm upgrade in CI. Instead, update the values file in Git and let the GitOps operator handle it.


Practical Setup: ArgoCD

# Install ArgoCD
kubectl create namespace argocd
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml

# Get initial admin password
kubectl get secret -n argocd argocd-initial-admin-secret \
  -o jsonpath="{.data.password}" | base64 --decode

# Port-forward the UI
kubectl port-forward svc/argocd-server -n argocd 8080:443

# Install CLI
brew install argocd

# Login
argocd login localhost:8080 --username admin --insecure

# Create application
argocd app create my-app \
  --repo https://github.com/myorg/my-app \
  --path k8s/production \
  --dest-server https://kubernetes.default.svc \
  --dest-namespace my-app \
  --sync-policy automated

Practical Setup: Flux

# Install Flux CLI
brew install fluxcd/tap/flux

# Bootstrap (installs Flux and pushes config to your Git repo)
flux bootstrap github \
  --owner=myorg \
  --repository=fleet \
  --branch=main \
  --path=clusters/production \
  --personal

# Flux now manages itself from your Git repo
# Add apps by creating CRDs in clusters/production/

When to Use Which

Use ArgoCD if:

  • Your team is operations-focused and will use the UI daily
  • You need strong RBAC for a large team with multiple environments
  • You’re investing in progressive delivery (Argo Rollouts)
  • You want the best multi-cluster management story (ApplicationSets)

Use Flux if:

  • You prefer everything-as-code with no UI
  • You want automatic image updates committed to Git
  • Resource efficiency matters (many small clusters)
  • You’re building a platform where tenant isolation is critical
  • You prefer the CNCF governance model

Neither alone: Many large organizations run both. ArgoCD manages cluster-scoped infrastructure (ingress, cert-manager, monitoring). Flux manages application deployments with image automation. They coexist without conflicts.


Common Patterns

The App-of-Apps Pattern (ArgoCD)

# Root application manages all other applications
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: root
  namespace: argocd
spec:
  source:
    path: argocd-apps   # Directory of Application CRDs
  syncPolicy:
    automated:
      prune: true
      selfHeal: true

Secrets Management

Neither tool handles secrets natively — you need to integrate with:

  • External Secrets Operator: Pulls from AWS SSM, Vault, GCP Secret Manager
  • Sealed Secrets: Encrypts secrets with a cluster key, safe to commit to Git
  • SOPS: Encrypt files with age/PGP keys, decrypt at sync time
# External Secrets with ArgoCD
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: db-credentials
spec:
  refreshInterval: 1h
  secretStoreRef:
    name: aws-secretsmanager
    kind: SecretStore
  target:
    name: db-credentials
  data:
  - secretKey: password
    remoteRef:
      key: prod/myapp/db
      property: password

Kubernetes Cluster Photo by Ales Nesetril on Unsplash


GitOps isn’t just a deployment methodology — it’s an operational philosophy. The best GitOps setup is the one your team will actually use. Both ArgoCD and Flux are excellent; pick based on your team’s preferences and operational requirements, not benchmarks.

이 글이 도움이 되셨다면 공감 및 광고 클릭을 부탁드립니다 :)