How Argo CD Manages Application Deployments: Inside the GitOps Controller

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. 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:

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) 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) 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 and 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

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) enables defining multiple sources in the sources list:

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:

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:


# 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), 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.
  • Three-stage pipeline: The repo-server (reposerver/server.go) renders sources into manifests, the sync controller (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. 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 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.

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 →