# Deep Dive into Argo CD Core Feature Functionalities: GitOps Controller Architecture Explained

> Explore Argo CD core functionalities and its GitOps controller architecture. Learn how Argo CD synchronizes Kubernetes clusters with Git-stored desired state through a six-stage pipeline.

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

---

**Argo CD continuously reconciles Git-stored desired state with live Kubernetes cluster state through a six-stage pipeline involving manifest generation, normalization, diff computation, and wave-based synchronization.**

The argoproj/argo-cd repository implements a declarative GitOps controller that automates application deployment and lifecycle management. Understanding its **Argo CD core feature functionalities** requires examining the controller package and gitops-engine library that orchestrate the reconciliation loop. The controller operates by pulling source repositories, computing diffs against live cluster state, and executing synchronized deployments while respecting ignore differences and sync wave configurations.

## Manifest Generation and Repository Resolution

Argo CD begins reconciliation by generating manifests from configured sources. The `GetRepoObjs` function in [`controller/state.go`](https://github.com/argoproj/argo-cd/blob/main/controller/state.go) coordinates with the repo-server to render templates for Helm, Kustomize, or plain YAML sources.

```go
// Simplified flow from controller/state.go
targetObjs, manifestInfos, revisionsMayHaveChanges, err :=
    m.GetRepoObjs(ctx, app, sources, appLabelKey, revisions,
                noCache, noRevisionCache, project.EffectiveSourceIntegrity(),
                project, true)

```

**Revision resolution** occurs through `ResolveRevision`, which converts ambiguous references like `HEAD` or `master` into concrete commit SHAs. When projects enforce **source integrity**, the `UpdateRevisionForPaths` RPC narrows revisions to only changes affecting the application's referenced paths.

## Target Normalization and Ignore Differences

Before computing diffs, Argo CD applies the `ignoreDifferences` specification through `NormalizeTargetObjects` in [`controller/state.go`](https://github.com/argoproj/argo-cd/blob/main/controller/state.go). This function:

- Removes ignored fields from **live** resources before diff calculation
- Copies ignored fields from live to target objects, excluding the `status` sub-resource

Configuration example for ignoring deployment annotations:

```yaml
spec:
  ignoreDifferences:
  - group: apps
    kind: Deployment
    jsonPointers:
    - /metadata/annotations

```

When configured, the diff engine treats changes to `metadata.annotations` as **in-sync**, preventing false drift detection on fields managed by external systems.

## Live State Retrieval and Permission Validation

The controller retrieves current cluster state via `GetManagedLiveObjs` from the `LiveStateCache`:

```go
liveObjByKey, err := m.liveStateCache.GetManagedLiveObjs(destCluster, app, targetObjs)

```

Resources are filtered against project allow/deny lists through `validateSyncPermissions`. Any resource not explicitly permitted by the AppProject configuration is excluded from reconciliation to enforce security boundaries.

## Diff Computation and Server-Side Reconciliation

Argo CD builds a `diff.Config` and invokes `argodiff.StateDiffs` to compute three-way diffs between desired and live states:

```go
diffResults, err := argodiff.StateDiffs(ctx,
    reconciliation.Live, reconciliation.Target, diffConfig)

```

**Server-side diff** activates when `ServerSideDiff=true`, utilizing dry-run kubectl apply operations to calculate changes without API server modification. When **structured merge diff** is enabled alongside `ServerSideApply=true`, the controller uses server-side apply mechanics for conflict resolution.

The diff configuration is constructed in [`controller/state.go`](https://github.com/argoproj/argo-cd/blob/main/controller/state.go) around line 470, incorporating ignore differences, resource overrides, and comparison options.

## Sync Execution and Wave Orchestration

The `SyncAppState` function in [`controller/sync.go`](https://github.com/argoproj/argo-cd/blob/main/controller/sync.go) orchestrates the actual synchronization:

```go
syncCtx, cleanup, err := sync.NewSyncContext(
    compareResult.syncStatus.Revision,
    reconciliationResult,
    restConfig,
    rawConfig,
    m.kubectl,
    app.Spec.Destination.Namespace,
    opts...)

```

**Sync waves** enable sequential resource application through the `syncWave` annotation. Resources group by wave number (default 0), applying in numerical order with configurable delays. The `ARGOCD_SYNC_WAVE_DELAY` environment variable controls pauses between waves (default 2 seconds):

```go
import (
    "os"
    "github.com/argoproj/argo-cd/v3/util/settings"
)

// Set a 5-second delay between sync waves
os.Setenv("ARGOCD_SYNC_WAVE_DELAY", "5")

```

**Pruning behavior** respects `PrunePropagationPolicy` and `PruneLast` settings, ensuring resource deletion occurs according to dependency requirements.

## Health Assessment and Status Updates

Post-sync, `setApplicationHealth` in [`controller/state.go`](https://github.com/argoproj/argo-cd/blob/main/controller/state.go) evaluates resource conditions:

```go
healthStatus, healthMessage, err := setApplicationHealth(
    managedResources, resourceSummaries, resourceOverrides,
    app, m.persistResourceHealth)

```

Individual resource health populates `Application.Status.Resources`, while aggregated application health (Healthy, Degraded, Missing, or Progressing) updates `Application.Status.Health`. The evaluation uses gitops-engine health rules customized through resource overrides.

## Practical Configuration Examples

### Server-Side Apply with Namespace Creation

```yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: nginx
spec:
  project: default
  source:
    repoURL: https://github.com/example/nginx
    targetRevision: HEAD
    path: ./manifests
  destination:
    server: https://kubernetes.default.svc
    namespace: nginx
  syncPolicy:
    syncOptions:
    - ServerSideApply=true
    - CreateNamespace=true

```

`ServerSideApply=true` forces the controller to use Kubernetes server-side apply during sync, while `CreateNamespace=true` enables automatic namespace provisioning.

### Sync Waves with PostSync Hooks

```yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: multi-wave
spec:
  source:
    repoURL: https://github.com/example/multi-wave
    targetRevision: main
    path: .
  destination:
    server: https://kubernetes.default.svc
    namespace: demo
  syncPolicy:
    syncOptions:
    - PruneLast=true
    - RespectIgnoreDifferences=true
    hooks:
    - exec:
        command: ["/bin/sh", "-c", "echo Post-hook"]
      type: PostSync
      syncWave: 2

```

The `PostSync` hook executes after wave 2 completes, while `PruneLast=true` ensures orphaned resources are deleted following successful wave application.

### Ignoring Container Image Changes

```yaml
spec:
  ignoreDifferences:
  - group: apps
    kind: Deployment
    jsonPointers:
    - /spec/template/spec/containers/0/image

```

This configuration prevents drift detection when container images are updated outside Git, common in CI/CD pipelines that mutate images during build processes.

## Key Source Files

| File | Responsibility |
|------|----------------|
| [`controller/state.go`](https://github.com/argoproj/argo-cd/blob/main/controller/state.go) | Manifest generation, target normalization, live state loading, diff computation, and health calculation |
| [`controller/sync.go`](https://github.com/argoproj/argo-cd/blob/main/controller/sync.go) | Sync operation orchestration, wave handling, server-side apply, and pruning logic |
| [`controller/sharding/sharding.go`](https://github.com/argoproj/argo-cd/blob/main/controller/sharding/sharding.go) | Workload distribution across controller replicas |
| `gitops-engine/pkg/sync` | Core diff, reconciliation, and resource-level sync primitives |
| `util/argo/diff` | Three-way diff implementation and configuration |
| `util/settings` | Centralized configuration for resource overrides and feature flags |

## Summary

- **Argo CD core feature functionalities** center on a deterministic six-stage reconciliation pipeline: manifest generation, target normalization, live state retrieval, diff computation, sync execution, and health assessment.
- The `GetRepoObjs` function in [`controller/state.go`](https://github.com/argoproj/argo-cd/blob/main/controller/state.go) handles repository resolution and template rendering, supporting Helm, Kustomize, and raw YAML sources.
- `NormalizeTargetObjects` applies `ignoreDifferences` configurations by selectively copying fields from live to target objects before diff calculation.
- `SyncAppState` in [`controller/sync.go`](https://github.com/argoproj/argo-cd/blob/main/controller/sync.go) orchestrates wave-based deployments with configurable delays through `ARGOCD_SYNC_WAVE_DELAY`.
- Server-side diff and server-side apply provide modern Kubernetes reconciliation mechanisms for complex field ownership scenarios.

## Frequently Asked Questions

### What is the Argo CD reconciliation loop?

The reconciliation loop is a continuous process where Argo CD compares desired state from Git repositories against live Kubernetes cluster state. According to the argoproj/argo-cd source code, the loop executes through [`controller/state.go`](https://github.com/argoproj/argo-cd/blob/main/controller/state.go), generating manifests, normalizing targets, computing diffs via `argodiff.StateDiffs`, and triggering synchronization when drift is detected. The loop runs at configured intervals or when triggered by webhook events.

### How does Argo CD handle sync waves?

Sync waves allow sequential resource deployment using the `syncWave` annotation (default 0). As implemented in [`controller/sync.go`](https://github.com/argoproj/argo-cd/blob/main/controller/sync.go), Argo CD applies resources in numerical wave order, waiting for each wave to complete before proceeding to the next. The `ARGOCD_SYNC_WAVE_DELAY` environment variable configures pauses between waves, while `PruneLast` ensures resource deletion occurs after all waves complete successfully.

### What is server-side diff in Argo CD?

Server-side diff is a comparison method enabled by `ServerSideDiff=true` that uses dry-run kubectl apply operations to calculate changes without modifying the API server. Implemented in the diff configuration logic of [`controller/state.go`](https://github.com/argoproj/argo-cd/blob/main/controller/state.go), this approach provides more accurate results for resources using server-side apply by simulating the actual merge process that would occur during synchronization.

### How does ignoreDifferences prevent false drift detection?

The `ignoreDifferences` specification prevents specific fields from triggering out-of-sync status through `NormalizeTargetObjects` in [`controller/state.go`](https://github.com/argoproj/argo-cd/blob/main/controller/state.go). This function removes configured fields from live objects before diff computation and copies current values into target objects (excluding status fields), ensuring the comparison treats ignored changes as in-sync regardless of cluster state mutations.