CoursesArgo CDIntermediate

Sync waves & hooks

Order and lifecycle jobs.

Advanced12 min · lesson 6 of 12

Real applications have ordering requirements — the CRD before the resource that uses it, the database migration before the new app version, the namespace before what goes in it. Argo CD sync waves control order: you annotate resources with a wave number, and Argo CD applies lower waves first, waiting for each wave to become healthy before the next. This lets one sync roll out a multi-part app in the correct sequence rather than applying everything at once.

ONE SYNC: PHASES & WAVES
1PreSync
hook Jobs (e.g. DB migration); failure aborts the sync
2Sync
apply by wave — lower waves first, wait for healthy
3PostSync
hook Jobs (e.g. smoke test) after main sync
4SyncFail
hooks that run only if the sync failed
Waves order the main sync; hooks run at each phase. A failing PreSync intentionally blocks the rollout.
resource annotations
metadata:
annotations:
argocd.argoproj.io/sync-wave: "-1" # runs before wave 0 (defaults)
# e.g. CRDs at wave -2, config at -1, the app at 0, smoke test at 1

Resource hooks

Argo CD also has sync hooks — resources (usually Jobs) that run at a phase of the sync: PreSync (before the main sync, e.g. a database migration), Sync (during), PostSync (after, e.g. a smoke test), and SyncFail. A failing PreSync hook aborts the sync, so a migration that must succeed before the new version rolls does exactly that. Hooks plus waves cover the ordering and lifecycle needs that a flat apply cannot express — the Argo CD analog of Helm hooks.

migration-job.yaml
apiVersion: batch/v1
kind: Job
metadata:
name: db-migrate
annotations:
argocd.argoproj.io/hook: PreSync # run before the app syncs
argocd.argoproj.io/hook-delete-policy: HookSucceeded
spec:
template:
spec: { restartPolicy: Never, containers: [{ name: migrate, image: app:1.4.0, command: ["/app/migrate"] }] }
A failing PreSync hook blocks the whole sync
PreSync hooks are meant to gate the rollout (migrate before deploy), so a hook failure intentionally aborts the sync and the new version does not roll — which is correct, but means a flaky or non-idempotent hook can wedge your deploys. Make hook Jobs idempotent and reliable, set a sensible hook-delete-policy so they clean up, and monitor them: the hook that guards your rollout is now on the critical path of every deploy.