Using Argo CD sync waves and hooks to enforce deterministic resource synchronization order for migrations, namespace creation, database and frontend deployment, and cleanup
In this lesson we explain how to use Argo CD sync waves together with sync hooks to control resource synchronization order. You’ll learn why hooks alone are not enough when you need strict sequencing (for example, run schema migration → data migration → namespace creation → PostgreSQL → frontend → cleanup) and how to combine hook phases and numeric sync-wave annotations to enforce that order.The repository contains a folder waves-demo under the synchronization path. That YAML contains multiple resources in a single manifest: two migration jobs (schema and data), a Namespace, frontend and PostgreSQL deployments and services, and a cleanup job.
High-level resource order in the manifest:
Schema migration job — currently annotated as a PreSync hook.
Namespace app-namespace.
Data migration job — also a PreSync hook.
Frontend deployment + frontend service.
PostgreSQL deployment + PostgreSQL service.
Cleanup job — annotated as a PostSync hook.
Baseline (trimmed) excerpt: the two jobs, the namespace, and a few deployment/service fragments. Note both migration jobs are PreSync hooks in this baseline, which causes them to run in parallel when Argo CD syncs the app.
Copy
# Baseline: both migration jobs use PreSync (they will run in parallel)apiVersion: batch/v1kind: Jobmetadata: name: schema-migration-job namespace: app-namespace annotations: argocd.argoproj.io/hook: PreSyncspec: template: spec: containers: - name: schema-migrator image: nginx:alpine command: - /bin/sh - -c - | echo 'Running schema migration...' sleep 1 echo 'Schema migration complete.' restartPolicy: Never backoffLimit: 2---apiVersion: v1kind: Namespacemetadata: name: app-namespace---apiVersion: batch/v1kind: Jobmetadata: name: data-migration-job namespace: app-namespace annotations: argocd.argoproj.io/hook: PreSyncspec: template: spec: containers: - name: data-migrator image: nginx:alpine command: - /bin/sh - -c - | echo 'Running data migration...' sleep 1 echo 'Data migration complete.' restartPolicy: Never backoffLimit: 2---# (further front-end & postgresql deployments/services omitted here for brevity)
If you deploy this baseline manifest as-is (without ordering), both PreSync jobs run concurrently. The frontend and PostgreSQL deployments are also created in parallel unless you control their order. The Argo CD UI will reflect concurrent sync activity:
When strict ordering is required (for example: schema migration → data migration → create namespace → PostgreSQL → frontend → cleanup), hooks alone are insufficient because multiple resources annotated with the same hook (e.g., PreSync) will run concurrently. Sync Waves provide the missing sequencing control.Argo CD supports a numeric annotation argocd.argoproj.io/sync-wave (string value) that defines relative ordering. Argo CD processes resources by increasing wave number (lowest first). The default wave is "0". Negative values run earlier than zero (for example, "-2" → "-1" → "0"). See the Argo CD sync waves documentation for details: https://argo-cd.readthedocs.io/en/stable/user-guide/sync-waves/
Sync waves and hook phases (PreSync/Sync/PostSync) are combinable: Argo CD groups resources by hook phase and wave, then processes groups in increasing wave order within each phase. Use this to implement precise, deterministic sync sequences.
Updated manifest: apply sync-wave annotations to enforce ordering. The planned sequence:
Commit the updated manifest (with sync-wave annotations) to Git before Argo CD can apply the new ordering.
If any PreSync hooks target the Namespace (i.e., run jobs in app-namespace), ensure the Namespace exists before the PreSync phase. Options:
Use —sync-option CreateNamespace=true when creating the Argo CD app, or
Make the Namespace a PreSync resource with an earlier wave value than the jobs.
Remember: multiple resources with the same hook phase and the same sync-wave value will be synced in parallel. Assign distinct sync-wave numbers to achieve strict, sequential ordering.
Summary
Hooks (PreSync/PostSync) control when resources run relative to the main sync phase, but resources sharing the same hook run concurrently.
Sync waves (argocd.argoproj.io/sync-wave) provide an ordered sequence within each hook phase and the sync phase.
Combine hooks and sync waves to implement complex GitOps workflows: migrations, namespace creation, database-first deployments, followed by frontend, and finishing with cleanup.