Argo CD GitOps Workflow Explained: 7 Stages from Repository to Cluster

Argo CD implements a declarative GitOps continuous-delivery pipeline that continuously watches Git repositories, renders manifests, computes diffs against live Kubernetes clusters, and automatically reconciles drift to ensure the cluster state always matches the version-controlled desired state.

Argo CD is an open-source continuous delivery tool maintained by the argoproj/argo-cd repository. It automates the deployment of applications to Kubernetes by treating Git as the single source of truth. Understanding the Argo CD GitOps workflow requires examining how the ApplicationController orchestrates the movement of declarative configurations from source control to running workloads.

The 7 Stages of the Argo CD GitOps Workflow

The Argo CD GitOps workflow operates as a continuous loop divided into seven discrete stages. Each stage is implemented by specific components within the controller codebase.

1. Source Fetch

The workflow begins when the ApplicationController detects a need to evaluate an Application custom resource. In controller/appcontroller.go (lines 18-23), the controller creates an ApplicationController struct that holds a RepoServer client. This client fetches the desired state from the configured Git repository, OCI registry, or other supported sources defined in the Application spec.

The controller supports polling intervals, webhooks, or manual triggers to initiate this fetch phase.

2. Manifest Generation (Hydration)

When the source contains template tools like Helm, Kustomize, or Jsonnet, the controller must render these "dry" configurations into plain Kubernetes YAML. This occurs in controller/hydrator/hydrator.go, where the hydrator implements the hydrator.Dependencies interface to execute the appropriate templating engine.

The output is a set of concrete Kubernetes manifests that represent the desired state without any templating directives remaining.

3. Diff and Health Analysis

Once manifests are generated, Argo CD compares them against the live objects in the target cluster. The gitops-engine/v3/pkg/diff package calculates the declarative differences, while gitops-engine/v3/pkg/health determines the health status of existing resources.

In controller/appcontroller.go (lines 438-447), the controller builds an argodiff.StateDiff structure that identifies drift between Git and the cluster. Any disparity marks the application as OutOfSync, while the health engine checks resource conditions like pod readiness or service availability.

4. Sync Decision

Based on the Application.Spec.SyncPolicy configuration and user requests, Argo CD decides whether to proceed with synchronization. The ApplicationController.requestAppRefresh method (lines 998-1016) enqueues refresh requests into the appRefreshQueue.

Auto-sync immediately applies changes when drift is detected. Manual sync requires explicit user approval through the CLI or UI. Skip maintains the current cluster state despite detected differences.

5. Apply Changes

When synchronization is approved, Argo CD generates a patch or full manifest and applies it to the target cluster using the Kubernetes client. The controller utilizes kube.Kubectl (referenced in controller/appcontroller.go lines 22-24) to execute these operations while respecting configured parallelism limits (lines 36-38) to prevent API server overload.

The apply process respects resource hooks, sync waves, and pruning settings to ensure ordered, atomic deployments.

6. Status Update

Following the sync operation, the controller updates the Application custom resource status with detailed results. The setAppManagedResources method (lines 998-1020 in controller/appcontroller.go) persists sync results, resource health, conditions, and the specific Git commit SHA that produced the live state.

This status update provides the user-facing representation of the deployment outcome and enables rollback to specific Git commits.

7. Event and Metrics Export

Every workflow execution generates audit events and Prometheus metrics. The argo.AuditLogger and metrics.MetricsServer are instantiated in NewApplicationController (lines 21-31), capturing operational data in controller/metrics/metrics.go.

These exports provide observability into sync frequencies, error rates, and resource consumption across the GitOps workflow.

Core Components and Source Code Architecture

The Argo CD GitOps workflow relies on a tightly integrated set of components distributed across the codebase:

  • controller/appcontroller.go – Main controller loop handling queue processing, sync orchestration, and reconciliation triggers.
  • controller/hydrator/hydrator.go – Renders Helm, Kustomize, and Jsonnet templates into canonical Kubernetes manifests.
  • gitops-engine/v3/pkg/diff – Calculates declarative differences between desired and live states, including logic to mask secret data.
  • gitops-engine/v3/pkg/health – Computes health status for Kubernetes resources based on their specific conditions.
  • controller/sharding/sharding.go – Distributes workload across multiple controller replicas for high availability.
  • util/db/db.go – Persists application state and sync history using a ConfigMap-backed database.
  • controller/metrics/metrics.go – Exposes Prometheus metrics and tracks kubectl resource usage.

Continuous Reconciliation Loop

Argo CD implements the Kubernetes informer pattern to maintain continuous awareness of both the Application CRD and the target cluster state. The ApplicationController runs a watch on these resources, enqueuing refresh requests into the appRefreshQueue whenever changes occur in Git (via webhook or polling) or when the live cluster deviates from the desired state.

Worker goroutines process this queue, invoking the seven-stage workflow to guarantee eventual consistency between the Git repository and the cluster. This architecture ensures that any manual changes made directly to the cluster (configuration drift) are automatically detected and reverted according to the sync policy.

Practical Example: Deploying an Application

The following Application resource demonstrates a complete GitOps configuration using Kustomize with automated reconciliation:

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: guestbook
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://github.com/argoproj/guestbook
    targetRevision: HEAD
    path: kustomize
  destination:
    server: https://kubernetes.default.svc
    namespace: default
  syncPolicy:
    automated:
      prune: true
      selfHeal: true

Execution flow:

  1. Fetch – The controller pulls the kustomize directory at HEAD from the repository.
  2. Hydrate – Kustomize renders the overlays into concrete Kubernetes manifests.
  3. Diff – argodiff.StateDiff compares generated manifests against the default namespace.
  4. Sync – With selfHeal enabled, drift automatically triggers kubectl apply operations.
  5. Verify – The Application status updates to Synced, recording the commit SHA and resource health.

Summary

  • Argo CD GitOps workflow centers on the ApplicationController in controller/appcontroller.go, which orchestrates seven distinct stages from source fetch to metrics export.
  • Source of truth is always the Git repository (or Helm/Kustomize source), enabling immutable history and audit trails.
  • Hydration converts dry templates to concrete YAML using controller/hydrator/hydrator.go before diffing occurs.
  • Continuous reconciliation via the informer pattern ensures the cluster automatically converges to the declared state, with sharding support for horizontal scalability.
  • Observability is built-in through Prometheus metrics and audit logging, providing full visibility into the deployment pipeline.

Frequently Asked Questions

How does Argo CD detect configuration drift in its GitOps workflow?

Argo CD detects drift through the gitops-engine/v3/pkg/diff package, which the ApplicationController invokes during the reconciliation loop. The controller builds an argodiff.StateDiff structure in controller/appcontroller.go (lines 438-447) that performs a server-side dry-run apply to compare the desired manifests from Git against live objects in the target cluster. Any detected differences mark the application as OutOfSync in the status field, triggering events or automated sync actions based on the configured policy.

What is the difference between manual sync and auto-sync in Argo CD?

Manual sync requires explicit user intervention through the Argo CD CLI, UI, or API to apply changes after drift is detected, allowing for review and approval before deployment. Auto-sync, configured via syncPolicy.automated in the Application spec, enables the controller to automatically apply changes when the requestAppRefresh method (lines 998-1016) detects drift, immediately reconciling the cluster state without human intervention.

How does Argo CD handle Helm and Kustomize templating during the workflow?

Argo CD processes Helm and Kustomize templates during the hydration stage using controller/hydrator/hydrator.go. The hydrator implements the hydrator.Dependencies interface to execute the appropriate tooling against the source files, rendering them into plain Kubernetes YAML before the diff analysis occurs. This allows Argo CD to compare the fully rendered desired state against the live cluster rather than comparing templates directly.

Can Argo CD manage applications across multiple Kubernetes clusters?

Yes, Argo CD supports multi-cluster deployments through the destination.server field in the Application spec, which can reference any cluster configured in the Argo CD settings. The controller uses the kube.Kubectl client (lines 22-24 in controller/appcontroller.go) to communicate with each target cluster's API server. For large-scale multi-cluster environments, controller/sharding/sharding.go distributes applications across multiple controller replicas to ensure scalability and high availability.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →