
September 10, 2026
11 min read
By Kokil Thapa | Last reviewed: September 2026
Sync Waves and Hooks in ArgoCD solve the hardest part of GitOps on Kubernetes: order. A flat Git repo with Deployments, CRDs, Jobs, and Ingress objects looks fine in version control. During sync, ArgoCD applies them in parallel unless you tell it otherwise. That race causes CRD-not-found errors, migrations running before Postgres exists, and ingress routing traffic to pods that are not ready yet. If you run ArgoCD GitOps for Kubernetes, waves and hooks are the control plane for safe rollout sequencing.
argocd.argoproj.io/sync-wave) run lower numbers first. Hooks (PreSync, Sync, PostSync, SyncFail) run Jobs or one-off resources at defined lifecycle points before or after the main wave sequence.What are Sync Waves and Hooks in ArgoCD?
ArgoCD reads your Git repo and reconciles each resource to the cluster. By default, it applies everything at once. Sync waves add a numeric priority. Hooks add lifecycle gates around that sequence.
Think of waves as lanes on a highway. Wave -5 clears before wave 0. Wave 0 clears before wave 5. Hooks are off-ramps: PreSync runs before any wave, PostSync runs after all waves succeed, and SyncFail runs when something breaks.
Both features use ArgoCD annotations on standard Kubernetes manifests. You do not need a separate controller or custom CRD. That keeps them compatible with Helm, Kustomize, and plain YAML in the same Application.
If you are comparing GitOps tools, see GitOps Flux vs ArgoCD for how Flux handles similar ordering with dependsOn instead of waves.
Sync waves in one sentence
A sync wave is an integer annotation. ArgoCD groups resources by wave value and applies each group only after the previous group reaches a healthy state.
Hooks in one sentence
A hook is a resource tagged with argocd.argoproj.io/hook. ArgoCD runs it at a lifecycle phase, waits for completion when configured, then continues or aborts the sync.
How do you configure sync waves in ArgoCD manifests?
Add the sync-wave annotation to any Kubernetes resource ArgoCD manages. Lower numbers run first. Most teams start CRDs and namespaces at negative waves and put ingress or HPA at positive waves.
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: widgets.example.com
annotations:
argocd.argoproj.io/sync-wave: "-1"
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: api
namespace: production
annotations:
argocd.argoproj.io/sync-wave: "0"
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: api-ingress
namespace: production
annotations:
argocd.argoproj.io/sync-wave: "2"
Wave values are strings in YAML but parse as integers. You can use large gaps like -100, 0, and 100 so you can insert new resources later without renumbering everything.
Helm and Kustomize patterns
With Helm, put annotations in values.yaml or template them in templates/*.yaml. With Kustomize, add a common annotation via patches or per-resource in the base.
# kustomization.yaml excerpt
patches:
- target:
kind: CustomResourceDefinition
patch: |-
- op: add
path: /metadata/annotations/argocd.argoproj.io~1sync-wave
value: "-2"
For multi-environment repos, keep wave numbers consistent across overlays. Dev and prod should share the same ordering logic even if replica counts differ. That prevents surprises when you promote manifests through GitOps across multiple clouds with ArgoCD.
Recommended wave layout
- Wave -3 to -2: Namespaces, NetworkPolicies, storage classes if managed in Git.
- Wave -1: CRDs and cluster-scoped operators.
- Wave 0: ConfigMaps, Secrets, Services, Deployments, StatefulSets.
- Wave 1: Jobs that must run after pods exist (non-hook Jobs).
- Wave 2+: Ingress, certificates, external-dns, HPA.
ArgoCD waits for resources in a wave to become healthy before starting the next wave. What "healthy" means depends on the resource type and your Application sync options.
What hook types does ArgoCD support and when should you use each?
Hooks solve tasks that do not fit a permanent Deployment. Migrations, backups, cache warms, and smoke tests belong here. ArgoCD supports four hook types documented in the official ArgoCD resource hooks guide.
| Hook type | Runs when | Typical use | Delete policy notes |
|---|---|---|---|
PreSync | Before any sync wave | DB backup, feature-flag snapshot | Often HookSucceeded |
Sync | During sync, with waves | One-off apply alongside a wave | Rare; prefer waves for long-lived resources |
PostSync | After all waves succeed | Smoke tests, Slack notification Job | HookSucceeded or BeforeHookCreation |
SyncFail | When sync fails | Rollback script, incident webhook | Keep idempotent; may run on partial failure |
A database migration Job is the classic PreSync or wave-0 hook example. You want it to finish before new app pods serve traffic.
apiVersion: batch/v1
kind: Job
metadata:
name: db-migrate
namespace: production
annotations:
argocd.argoproj.io/hook: PreSync
argocd.argoproj.io/hook-delete-policy: HookSucceeded
argocd.argoproj.io/sync-wave: "0"
spec:
template:
spec:
restartPolicy: Never
containers:
- name: migrate
image: myapp:1.4.2
command: ["php", "artisan", "migrate", "--force"]
The hook-delete-policy controls cleanup. HookSucceeded removes the Job after success so the next sync can create a fresh one. BeforeHookCreation deletes any previous hook resource before a new sync starts. Without a delete policy, old hook Jobs pile up and block name collisions.
PreSync vs PostSync decision rule
Use PreSync when the cluster must be prepared before manifests apply. Use PostSync when validation needs the full stack running. Use SyncFail for cleanup or paging — pair it with Alertmanager alerting patterns for production visibility.
Hook resources are often Jobs or bare Pods. ConfigMaps and Secrets can be hooks too if you need temporary config injected only during sync.
How do sync waves and hooks interact during an ArgoCD sync?
The interaction rules matter because misconfigured hooks stall syncs indefinitely. ArgoCD runs PreSync hooks first, sorted by sync-wave among hooks of the same type. Then it processes regular resources wave by wave. PostSync hooks run last, again sorted by wave.
A hook can also carry a sync-wave annotation. Among PreSync hooks, wave -1 runs before wave 0. That lets you chain backup then migration before the main manifest rollout.
metadata:
annotations:
argocd.argoproj.io/hook: PreSync
argocd.argoproj.io/sync-wave: "-1"
argocd.argoproj.io/hook-delete-policy: BeforeHookCreation,HookSucceeded
ArgoCD waits for hook Jobs to complete when argocd.argoproj.io/hook-delete-policy includes success semantics and the Job reaches Complete. Failed Jobs fail the sync unless you override health checks.
Sync options that change behaviour
Application-level sync options alter wave and hook semantics:
ApplyOutOfSyncOnly=trueskips unchanged resources but hooks still run when triggered.Replace=trueforces recreate; use carefully with StatefulSets.PruneLast=truedeletes removed resources after all waves succeed.RespectIgnoreDifferences=truehonours ignore rules during health checks.
Set these in the Application manifest or the AppProject defaults. Document them in your repo README so the next engineer does not debug a "stuck" sync blind.
For a full Application setup walkthrough, read set up GitOps with ArgoCD and declarative Kubernetes deployments with ArgoCD.
Health checks and stuck syncs
ArgoCD uses Lua health scripts per resource type. A Job hook must reach Completed. If your Job succeeds but ArgoCD marks it Progressing, check custom health overrides in argocd-cm ConfigMap.
Timeout settings live at the Application and global level. A migration that runs 20 minutes needs timeout.reconciliation and hook Job activeDeadlineSeconds aligned. Otherwise ArgoCD cancels the sync while the database is mid-transaction.
What are common mistakes when using ArgoCD sync waves and hooks?
Most production incidents around ordering are self-inflicted. The annotations are simple; the edge cases are not.
Same wave number on dependencies
Two resources at wave 0 apply in parallel. If Service A needs ConfigMap B, put ConfigMap B at wave -1 or lower. Never assume file order in Git implies apply order.
Forgotten hook delete policies
A PreSync Job without delete policy blocks the next sync because the resource name already exists. Always set hook-delete-policy. Test a second consecutive sync in staging, not just the first deploy.
Hooks that never terminate
Interactive containers or Jobs waiting on external approval hang the sync. Hooks should exit with code 0 or fail fast. For human gates, use ArgoCD manual sync or a pull-request check instead of a sleeping Job.
CRDs and operators racing
Installing an operator Deployment at wave 0 while its CRD is also wave 0 fails randomly. CRDs belong at -1 or lower. Wait for Established condition before custom resources at 0.
Validating before ArgoCD sees the commit
Run schema validation in CI. A broken hook annotation wastes time in the cluster. Use a JSON formatter locally to inspect rendered Helm output, then kubeconform or conftest against your manifests.
Admission webhooks on the cluster add another ordering layer. See admission controllers and validating webhooks for how mutating webhooks interact with ArgoCD apply.
Multi-source Applications
ArgoCD multi-source Apps merge manifests from several refs. Waves apply globally across all sources. Keep wave conventions shared across repos so a platform team and app team do not both claim wave 0 for unrelated resources.
For teams running PHP or Laravel on Kubernetes, the same ordering applies to migration Jobs and Horizon workers. Platform work still benefits from Linux system administration discipline around logs, timeouts, and rollback — whether Deployer handles the VM or ArgoCD handles the cluster.
Observability
Export ArgoCD metrics to Prometheus. Alert on argocd_app_sync_total{phase="Failed"} and sync duration spikes. Wire SyncFail hooks to your incident channel. Treat sync history in the UI as an audit log during postmortems.
The ArgoCD sync waves documentation and the Kubernetes CRD lifecycle guide are the authoritative references when behaviour differs across ArgoCD versions.
Key Takeaways
- Assign negative sync waves to CRDs, namespaces, and operators; keep app workloads at wave
0and edge resources at wave1+. - Use PreSync hooks for migrations and backups; use PostSync hooks for smoke tests after all waves succeed.
- Always set
argocd.argoproj.io/hook-delete-policyon hook Jobs so repeat syncs do not collide on resource names. - Combine hook type and sync-wave on the same resource when you need ordered steps inside the PreSync or PostSync phase.
- Test the second sync in staging — first-deploy success hides missing delete policies and timeout mismatches.
- Validate rendered manifests in CI and alert on failed Application sync phases before users hit broken endpoints.
People Also Ask
What is the default sync wave in ArgoCD?
Resources without the annotation behave as wave 0. They sync together in parallel with other wave-0 objects. Explicit waves are only needed when order matters.
Can Helm hooks replace ArgoCD hooks?
Helm hooks run during helm template driven installs, not during ArgoCD's kubectl apply loop. When ArgoCD deploys Helm charts, prefer ArgoCD sync waves and hooks annotations on rendered resources or use the Argo CD Helm plugin patterns from your chart pipeline.
Do sync waves work with automated sync?
Yes. Automated sync respects waves and hooks on every reconciliation. A failed PostSync hook marks the Application OutOfSync or Degraded depending on settings, which stops silent partial rollouts.
How is Flux ordering different from ArgoCD sync waves?
Flux uses dependsOn between Kustomizations and health checks on resources. ArgoCD uses numeric waves and hook phases on individual manifests. Both solve ordering; ArgoCD's model is annotation-driven per resource. Compare approaches in FluxCD vs ArgoCD GitOps compared.
Ship ordered GitOps rollouts with confidence
Sync Waves and Hooks in ArgoCD turn a flat manifest repo into a sequenced deployment pipeline. Start with a wave chart in your platform docs, add PreSync migration Jobs with delete policies, and finish with PostSync smoke tests. That three-layer pattern prevents most ordering bugs without custom operators.
If you are adopting GitOps for client platforms or migrating from script-based deploys, structured rollout order is non-negotiable. See the Adventure Third Pole Trek booking platform for the kind of production application that depends on reliable release mechanics, or review support and maintenance services for ongoing cluster and application care.
Need help designing GitOps workflows, CI validation, or Kubernetes rollout strategy for your team? Contact us to discuss your stack, sync policies, and production requirements.
Frequently Asked Questions
0 Comments
Leave a comment
Your email is not published. Comments appear once they have been read. Sign in to have your details filled in.

