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

> Explore the Argo CD GitOps workflow in 7 stages. Discover how Argo CD continuously syncs your Kubernetes clusters with your Git repository for automated, declarative deployments.

- Repository: [Argo Project/argo-cd](https://github.com/argoproj/argo-cd)
- Tags: deep-dive
- Published: 2026-07-15

---

**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](https://github.com/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`](https://github.com/argoproj/argo-cd/blob/main/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`](https://github.com/argoproj/argo-cd/blob/main/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`](https://github.com/argoproj/argo-cd/blob/main/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`](https://github.com/argoproj/argo-cd/blob/main/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`](https://github.com/argoproj/argo-cd/blob/main/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`](https://github.com/argoproj/argo-cd/blob/main/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`](https://github.com/argoproj/argo-cd/blob/main/controller/appcontroller.go)** – Main controller loop handling queue processing, sync orchestration, and reconciliation triggers.
- **[`controller/hydrator/hydrator.go`](https://github.com/argoproj/argo-cd/blob/main/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`](https://github.com/argoproj/argo-cd/blob/main/controller/sharding/sharding.go)** – Distributes workload across multiple controller replicas for high availability.
- **[`util/db/db.go`](https://github.com/argoproj/argo-cd/blob/main/util/db/db.go)** – Persists application state and sync history using a ConfigMap-backed database.
- **[`controller/metrics/metrics.go`](https://github.com/argoproj/argo-cd/blob/main/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:

```yaml
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`](https://github.com/argoproj/argo-cd/blob/main/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`](https://github.com/argoproj/argo-cd/blob/main/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`](https://github.com/argoproj/argo-cd/blob/main/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`](https://github.com/argoproj/argo-cd/blob/main/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`](https://github.com/argoproj/argo-cd/blob/main/controller/appcontroller.go)) to communicate with each target cluster's API server. For large-scale multi-cluster environments, [`controller/sharding/sharding.go`](https://github.com/argoproj/argo-cd/blob/main/controller/sharding/sharding.go) distributes applications across multiple controller replicas to ensure scalability and high availability.