# How Argo CD Manages Application Deployments: Inside the GitOps Controller

> Discover how Argo CD manages application deployments using GitOps. Learn about its reconciliation process, rendering, diffing, and synchronized apply operations for efficient Kubernetes management.

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

---

**Argo CD manages application deployments by treating them as Kubernetes Custom Resources called `Application`, where a controller continuously reconciles the live cluster state with the desired state defined in Git repositories through a three-stage pipeline of source rendering, diff computation, and synchronized apply operations.**

Argo CD is a declarative, GitOps continuous delivery tool for Kubernetes that automates the deployment of applications to specified target environments. Understanding how Argo CD manages application deployments reveals why it has become the standard for GitOps workflows, leveraging a sophisticated controller architecture that ensures cluster state matches version-controlled configurations.

## The Application Custom Resource

At the core of Argo CD's deployment management is the **Application Custom Resource (CR)**, defined in [`pkg/apis/application/v1alpha1/types.go`](https://github.com/argoproj/argo-cd/blob/main/pkg/apis/application/v1alpha1/types.go). This resource acts as the single source of truth for what should be running in your cluster.

### Defining Desired State

The `ApplicationSpec` struct encapsulates everything needed to deploy an application:

- **`Source`** or **`Sources`**: Points to the Git repository URL, path, and revision (branch, tag, or commit SHA)
- **`Destination`**: Specifies the target Kubernetes cluster (`ApplicationDestination`) and namespace
- **`SyncPolicy`**: Controls automation settings including auto-sync, pruning, and self-healing
- **Source-specific configs**: Helm values, Kustomize patches, or Jsonnet parameters

The controller uses helper methods like `IsHelm()`, `IsOCI()`, and `AllowsConcurrentProcessing()` to determine how to process the source based on the `ApplicationSource` type.

Here is a complete `Application` definition that deploys a Helm chart with automated sync policies:

```yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: guestbook
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://github.com/argoproj/argocd-example-apps
    path: guestbook
    targetRevision: HEAD
    helm:
      valueFiles:
        - values-prod.yaml
  destination:
    server: https://kubernetes.default.svc
    namespace: guestbook
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
    retry:
      limit: 5
      backoff:
        duration: 5s
        factor: 2
        maxDuration: 3m

```

## The Three-Stage Deployment Pipeline

Argo CD manages deployments through a tightly-coupled reconciliation loop consisting of three distinct stages. This pipeline is orchestrated by the **application controller**, which watches `Application` CRs and drives the cluster toward the declared state.

### Stage 1: Source Retrieval and Manifest Rendering

The process begins when the controller detects an `Application` resource or a Git repository update. The **repo-server** ([`reposerver/server.go`](https://github.com/argoproj/argo-cd/blob/main/reposerver/server.go)) handles the heavy lifting of source processing:

1. **Clone**: Fetches the repository at the specified `targetRevision`
2. **Generate**: Runs the appropriate generator based on the source type:
   - **Helm**: Renders templates with provided values
   - **Kustomize**: Applies kustomization overlays
   - **Jsonnet**: Executes jsonnet templates
   - **Plain YAML**: Parses raw manifests
3. **Return**: Produces a set of `unstructured.Unstructured` manifest objects ready for cluster application

The repo-server respects concurrency controls through `ApplicationSource.AllowsConcurrentProcessing()`, which disables parallel processing for certain complex Kustomize configurations involving images or label transformations.

### Stage 2: Diff and Sync Planning

Once manifests are rendered, the **sync controller** ([`controller/sync.go`](https://github.com/argoproj/argo-cd/blob/main/controller/sync.go)) performs sophisticated state analysis:

- **Fetch Live State**: Retrieves current objects from the target cluster using the dynamic client
- **Compute Diff**: Utilizes `gitops-engine/pkg/diff` to compare desired manifests against live resources, identifying creates, updates, and deletes
- **Apply Ignore Rules**: Respect `ignore-differences` annotations and configuration
- **Build Operation**: Creates a `SyncOperation` (`sync.Operation`) based on `ApplicationSpec.SyncPolicy`, determining the exact sequence of kubectl-like apply calls needed

The controller persists this operation plan in `Application.Status.OperationState`, ensuring traceability and crash recovery.

### Stage 3: Apply and Reconcile

The final stage executes the planned changes and verifies outcomes:

- **Resource Hooks**: Processes pre-sync, sync, and post-sync hooks defined in [`controller/sort_delete.go`](https://github.com/argoproj/argo-cd/blob/main/controller/sort_delete.go) and [`controller/sharding/sharding.go`](https://github.com/argoproj/argo-cd/blob/main/controller/sharding/sharding.go) to run jobs or scripts at specific lifecycle points
- **Apply**: Issues dynamic client calls to create or update resources, respecting sync waves for ordered deployment
- **Health Assessment**: Runs `gitops-engine/v3/pkg/health` checks to determine resource readiness (e.g., Deployment rollout completion, Pod readiness)
- **Status Update**: Writes results to `ApplicationStatus.Sync` and `ApplicationStatus.Health` fields tracked in [`controller/state.go`](https://github.com/argoproj/argo-cd/blob/main/controller/state.go)

The loop repeats automatically on any trigger—repository webhooks, cluster drift detection, polling intervals, or explicit `argocd app sync` commands.

## Key Configuration Patterns

### Multi-Source Applications

Modern deployments often require combining multiple Git repositories or Helm charts. The `ApplicationSpec.HasMultipleSources()` method (lines 94-96 in [`types.go`](https://github.com/argoproj/argo-cd/blob/main/types.go)) enables defining multiple sources in the `sources` list:

```yaml
spec:
  sources:
    - repoURL: https://github.com/argoproj/argocd-example-apps
      path: guestbook
      targetRevision: HEAD
    - repoURL: https://github.com/argoproj/argocd-example-apps
      path: helm
      targetRevision: v1.2.3
      helm:
        valueFiles:
          - values-prod.yaml

```

The controller renders each source in parallel (when `AllowsConcurrentProcessing()` returns true) and merges the resulting manifests before diffing.

### Resource Hooks and Sync Waves

For complex deployment scenarios requiring database migrations or cache warm-ups, Argo CD supports **resource hooks**:

```yaml
metadata:
  name: init-job
  annotations:
    argocd.argoproj.io/hook: PreSync
spec:
  template:
    spec:
      containers:
        - name: migrate
          image: migrate-tool:latest
          command: ["sh", "-c", "run-migrations"]
      restartPolicy: Never

```

Hooks are processed by the sync controller before, during, or after the main resource synchronization, with **Sync Waves** controlling the exact ordering within each phase.

### Tracking Methods and Drift Detection

Argo CD employs three tracking methods to match live objects to generated manifests: `TrackingMethodAnnotation`, `TrackingMethodLabel`, and `TrackingMethodAnnotationAndLabel`. This tracking ensures that when **Self-Heal** is enabled in the `SyncPolicy`, the controller can detect manual cluster changes and automatically reapply the Git-defined state.

## Practical CLI Operations

Deploy applications interactively using the Argo CD CLI, which ultimately creates and modifies the same `Application` CRs:

```bash

# Authenticate with the API server

argocd login <ARGOCD_SERVER> --username admin --password <PASS>

# Create an application with automated sync policies

argocd app create guestbook \
  --repo https://github.com/argoproj/argocd-example-apps \
  --path guestbook \
  --dest-server https://kubernetes.default.svc \
  --dest-namespace guestbook \
  --sync-policy automated \
  --auto-prune \
  --self-heal

# Trigger manual synchronization with pruning

argocd app sync guestbook --prune

# Monitor deployment status

argocd app get guestbook

```

These commands interact with the Argo CD API server ([`cmd/argocd-server/commands/argocd_server.go`](https://github.com/argoproj/argo-cd/blob/main/cmd/argocd-server/commands/argocd_server.go)), which exposes endpoints for CRUD operations on `Application` resources.

## Summary

- **Argo CD manages application deployments** through the `Application` Custom Resource, which stores desired state in [`pkg/apis/application/v1alpha1/types.go`](https://github.com/argoproj/argo-cd/blob/main/pkg/apis/application/v1alpha1/types.go).
- **Three-stage pipeline**: The repo-server ([`reposerver/server.go`](https://github.com/argoproj/argo-cd/blob/main/reposerver/server.go)) renders sources into manifests, the sync controller ([`controller/sync.go`](https://github.com/argoproj/argo-cd/blob/main/controller/sync.go)) computes diffs and plans operations, and the reconciliation loop applies changes while updating health status.
- **Automated policies** controlled via `SyncPolicy` enable self-healing drift correction and automatic pruning of orphaned resources.
- **Multi-source support** allows combining multiple Git repositories or Helm charts, rendered in parallel when concurrency is allowed.
- **Resource tracking** methods and hooks provide granular control over deployment orchestration and lifecycle management.

## Frequently Asked Questions

### What is the difference between Hard Refresh and Normal Refresh in Argo CD?

**Normal Refresh** (`RefreshTypeNormal`) fetches the current state from the target cluster and compares it against the cached manifest generation, suitable for detecting cluster drift. **Hard Refresh** (`RefreshTypeHard`) forces the repo-server to re-clone the Git repository and regenerate all manifests from scratch, bypassing any cached results. Use Hard Refresh when you suspect the repo-server cache contains stale data or when troubleshooting manifest generation issues.

### How does Argo CD handle Helm charts versus plain YAML deployments?

**Argo CD detects the source type** through methods like `IsHelm()` and `IsOCI()` defined in [`types.go`](https://github.com/argoproj/argo-cd/blob/main/types.go). For Helm charts, the repo-server runs `helm template` with the provided `valueFiles` and parameters, rendering Kubernetes manifests before the diff stage. For plain YAML, it parses the files directly without template processing. Both result in `unstructured.Unstructured` objects that follow the same synchronization pipeline.

### What happens when a live resource drifts from the desired Git state?

When **Self-Heal** is enabled in the `SyncPolicy`, the controller detects drift during its regular reconciliation loop (or manual refresh) and automatically triggers a sync operation to reapply the Git-defined configuration. This process involves recomputing the diff in [`controller/sync.go`](https://github.com/argoproj/argo-cd/blob/main/controller/sync.go) and executing the necessary kubectl-like apply calls to convergence. If Self-Heal is disabled, the `Application` status will show `OutOfSync` until an administrator manually triggers synchronization.

### How does Argo CD manage concurrent processing for multiple sources?

**Multi-source applications** use the `HasMultipleSources()` check and process each entry in the `sources` list independently. The controller evaluates `AllowsConcurrentProcessing()` for each source—certain configurations like Kustomize with image transformers disable parallelism to prevent race conditions. When allowed, the repo-server renders sources concurrently, significantly speeding up the manifest generation phase for complex applications combining Helm charts and Kustomize overlays.