Interactive · GitOps · Argo CD

An Argo CD sync, step by step

Argo CD doesn't really "deploy" — it continuously reconciles, comparing the desired state in Git against the live state in the cluster and, when they differ, running a sync operation through ordered phases until the cluster matches Git and every resource is healthy. One architecture diagram stays fixed below while its state steps through a full sync: from steady state, through drift detection, into PreSync → Sync → PostSync, to Synced + Healthy — plus the failure branch. Thick grey lines are the fixed wiring; the thin blue overlay is the desired-state path (Git → repo-server → controller) and the thin teal overlay is the live-state path (controller ↔ cluster). A violet ring marks the component doing the work. Watch three things change: which component is active, the Sync status, and the Health status.

R reconcile — detect drift S sync operation — apply & verify F failure — the branch that pages you
View
The Argo CD control plane — a fixed diagram whose sync state changes per stage Git (external, left) feeds the desired-state path into the API server, repo-server and application controller inside the Argo CD control plane; the controller connects along the live-state path to an external Kubernetes cluster on the right, with Redis as a cache and Dex dimmed as auth-only. Across the eleven stages the blue desired-state overlay and teal live-state overlay light up, animate, or dim; a violet ring moves to the active component; and an operation-phase badge plus the Sync and Health read-outs change from Synced/Healthy through OutOfSync and Progressing to the SyncFail failure branch. Argo CD control plane desired-state path live-state path Git repo desired state source of truth · external API Server argocd-server · triggers · webhooks Redis throw-away cache Repo Server renders manifests (desired) Dex · SSO auth only — not in sync path Application Controller reconcile · diff · apply · run hooks · assess health op: — Kubernetes cluster live state · kube-apiserver where manifests are applied · external

Sync status

Health status

Operation phase

Sync phase / wave

What's happening

physical wiring (always present) desired-state path live-state path external / cache active component ok in progress failed

1 · Status vocabularies

The three state machines Argo CD reports, using its exact names. App-level Health is the worst health of its immediate child resources, not an inherited value.

DimensionValues (verbatim)Notes
Sync status (3)Synced OutOfSync UnknownSynced = live matches Git; OutOfSync = mismatch; Unknown = comparison not available.
Health status (6)Healthy Progressing Degraded Suspended Missing UnknownPriority (worst wins): Healthy < Suspended < Progressing < Missing < Degraded < Unknown.
Operation phase (5)Running Succeeded Failed Error TerminatingRecorded in status.operationState on the Application.

2 · Sync phases, hooks & annotations

A sync runs in ordered phases. Apply order within a sync is: phase → sync-wave → kind → name. PostSync fires only after a successful apply and every resource is Healthy.

ItemValueMeaning
PhasesPreSyncSyncPostSync (+ SyncFail)PreSync runs before manifests; Sync applies them; PostSync runs after all resources are Healthy; SyncFail runs on failure.
Hook annotationargocd.argoproj.io/hookValues: PreSync Sync Skip PostSync SyncFail PostDelete.
Hook delete policyargocd.argoproj.io/hook-delete-policyHookSucceeded · HookFailed · BeforeHookCreation.
Sync waveargocd.argoproj.io/sync-waveInteger, default 0, negatives allowed; low → high, ~2s delay between waves; next wave waits for current to be Healthy.

3 · Triggers & the reconciliation loop

What wakes the controller, and how often it looks on its own.

TriggerMechanismNotes
Manualargocd app sync, UI or APIExplicit; also the only mode that permits rollback.
Automatedspec.syncPolicy.automatedOptions: prune, selfHeal, allowEmpty. Only syncs when OutOfSync; skips identical SHAs unless selfHeal.
Polltimeout.reconciliation~3 min (120s + up to 60s jitter). Set 0 to disable polling entirely.
WebhookGit provider pushNear-instant sync instead of waiting for the poll tick.

4 · Sync options & argocd app sync flags

How the apply behaves, set per-app via argocd.argoproj.io/sync-options or per-run via CLI flags. Retry uses exponential backoff.

Sync optionsCLI flagsRetry / backoff
Prune=true · Replace=true · Force=true · ServerSideApply=true · ApplyOutOfSyncOnly=true · CreateNamespace=true · PrunePropagationPolicy=<p> · PruneLast=true --prune · --force · --replace · --server-side · --dry-run · --resource · --async spec.syncPolicy.retry.limit (e.g. 5; -1=unlimited)
backoff.duration 5s · factor 2 · maxDuration 3m

5 · Three failure modes

The ways a real sync goes wrong — stage F is the first of these.

ModeWhat happensSymptom
Hook failureA PreSync/Sync hook Job fails (classic: a DB-migration Job errors), so the Sync phase never applies; SyncFail hooks run.OperationState = Failed, stays OutOfSync.
Stuck ProgressingA resource never reaches Healthy, so PostSync never fires and the operation hangs or times out.Synced but Degraded / Progressing.
selfHeal vs humanSomeone kubectl edits a live resource; with selfHeal: true the controller reverts it within ~5s, repeatedly.Manual changes never stick.