Kokil Thapa - Professional Web Developer in Nepal
Freelancer Web Developer in Nepal with 15+ Years of Experience

Kokil Thapa is an experienced full-stack web developer focused on building fast, secure, and scalable web applications. He helps businesses and individuals create SEO-friendly, user-focused digital platforms designed for long-term growth.

Sync Waves and Hooks in ArgoCD

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.

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.

ArgoCD Sync PipelinePreSync HookDB backup JobWave -2NamespacesWave -1CRDsWave 0App stackWave 1IngressPostSync HookSmoke test JobSyncFail hook runs if any wave or hook fails — triggers rollback or alertGit commit → ArgoCD Application → ordered reconcile
Sync Waves and Hooks in ArgoCD form a ordered pipeline from PreSync through numbered waves to PostSync validation

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.

  1. Wave -3 to -2: Namespaces, NetworkPolicies, storage classes if managed in Git.
  2. Wave -1: CRDs and cluster-scoped operators.
  3. Wave 0: ConfigMaps, Secrets, Services, Deployments, StatefulSets.
  4. Wave 1: Jobs that must run after pods exist (non-hook Jobs).
  5. 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 typeRuns whenTypical useDelete policy notes
PreSyncBefore any sync waveDB backup, feature-flag snapshotOften HookSucceeded
SyncDuring sync, with wavesOne-off apply alongside a waveRare; prefer waves for long-lived resources
PostSyncAfter all waves succeedSmoke tests, Slack notification JobHookSucceeded or BeforeHookCreation
SyncFailWhen sync failsRollback script, incident webhookKeep 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.

ArgoCD Hook Types TimelineSync startSync endPreSyncSync Waves-2 → -1 → 0 → 1 → 2PostSyncSyncFailOnly on failure path
ArgoCD hook types map to distinct points in the sync lifecycle relative to numbered sync waves

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.

Wave or Hook?Resource long-lived?YesUse sync-waveDeployment, CRD, IngressNoOne-off task?Use hook JobMigrate, test, notifyNeeds strict order?Combine bothValidate YAML in CI with kubeconform before ArgoCD sync
Decision tree for Sync Waves and Hooks in ArgoCD — long-lived resources get waves, one-off tasks get hooks

Sync options that change behaviour

Application-level sync options alter wave and hook semantics:

  • ApplyOutOfSyncOnly=true skips unchanged resources but hooks still run when triggered.
  • Replace=true forces recreate; use carefully with StatefulSets.
  • PruneLast=true deletes removed resources after all waves succeed.
  • RespectIgnoreDifferences=true honours 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.

Before: parallel syncAfter: waves + hooksCRD + App same momentCRD not found errorsMigration after trafficRandom sync failuresWave -1 CRD firstPreSync migration JobWave 0 app DeployPostSync smoke testfixProduction checklistTest second sync · Set delete policy · Align Job timeoutDocument wave scheme · Validate in CI · Monitor SyncFailPair with Prometheus alerts on Application sync status
Sync Waves and Hooks in ArgoCD eliminate parallel-sync race conditions common in unstructured GitOps repos

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 0 and edge resources at wave 1+.
  • Use PreSync hooks for migrations and backups; use PostSync hooks for smoke tests after all waves succeed.
  • Always set argocd.argoproj.io/hook-delete-policy on 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

Sync Waves and Hooks in ArgoCD control apply order during a sync. Sync waves use the annotation argocd.argoproj.io/sync-wave so lower numbers run first and ArgoCD waits for each wave to become healthy before the next. Hooks use argocd.argoproj.io/hook to run one-off resources at lifecycle phases: PreSync before waves, Sync during, PostSync after all waves succeed, and SyncFail on failure. Both are standard Kubernetes annotations, so they work with plain YAML, Helm, and Kustomize in the same Application without a separate controller.

Resources without the sync-wave annotation behave as wave 0. They apply in parallel with other wave-0 objects. Add explicit waves only when order matters.

Add argocd.argoproj.io/sync-wave to any resource ArgoCD manages, using lower integers for earlier steps. Wave values are strings in YAML but parse as integers; large gaps like -100, 0, and 100 leave room to insert resources later. With Helm, put annotations in values.yaml or templates. With Kustomize, use patches or per-resource base annotations. Keep wave numbers consistent across dev and prod overlays so promoted manifests keep the same ordering logic.

ArgoCD supports four hook types. PreSync runs before any sync wave for backups, snapshots, or prep work. Sync runs during sync alongside waves and is rare for long-lived resources. PostSync runs after all waves succeed for smoke tests or notifications. SyncFail runs when sync fails for rollback scripts or incident webhooks and should stay idempotent. Database migration Jobs are a classic PreSync example. Hook resources are often Jobs or Pods, though ConfigMaps and Secrets can be hooks for temporary sync-time config.

The hook-delete-policy controls cleanup of hook resources between syncs. 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 can block the next sync through name collisions. Always set hook-delete-policy on PreSync Jobs. Test a second consecutive sync in staging, not just the first deploy, because first-deploy success often hides missing delete policies.

ArgoCD runs PreSync hooks first, sorted by sync-wave among hooks of the same type. It then processes regular resources wave by wave, waiting for each wave to reach a healthy state before starting the next. PostSync hooks run last, again sorted by wave. A hook can also carry a sync-wave annotation, so among PreSync hooks wave -1 runs before wave 0, letting you chain backup then migration before the main rollout. ArgoCD waits for hook Jobs to complete when delete policy includes success semantics and the Job reaches Complete. Failed Jobs fail the sync unless health checks are overridden.

Use PreSync when the cluster must be prepared before manifests apply, such as database backups, feature-flag snapshots, or migrations that must finish before new app pods serve traffic. Use PostSync when validation needs the full stack running, such as smoke tests or Slack notifications after ingress and workloads are up. Use SyncFail for cleanup or paging when something breaks. For human approval gates, prefer ArgoCD manual sync or pull-request checks instead of a Job that sleeps indefinitely and stalls the sync.

A practical wave chart most teams follow: wave -3 to -2 for namespaces, NetworkPolicies, and storage classes managed in Git; wave -1 for CRDs and cluster-scoped operators; wave 0 for ConfigMaps, Secrets, Services, Deployments, and StatefulSets; wave 1 for Jobs that must run after pods exist when they are not hooks; wave 2 and above for Ingress, certificates, external-dns, and HPA. ArgoCD waits for resources in each wave to become healthy before starting the next, though what healthy means depends on resource type and Application sync options.

No. Helm hooks run during helm-driven installs, not during ArgoCD's kubectl apply loop. Prefer ArgoCD sync waves and hook annotations on rendered resources when ArgoCD deploys Helm charts.

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.

Flux uses dependsOn between Kustomizations plus health checks on resources to enforce order. ArgoCD uses numeric sync-wave annotations and hook phases on individual manifests. Both solve GitOps ordering problems, but ArgoCD's model is annotation-driven per resource rather than dependency links between Kustomization objects. Choose based on whether your team wants ordering declared on each YAML file or chained at the Kustomization layer in Flux.

The most frequent production incidents are self-inflicted. Putting dependent resources at the same wave number causes parallel apply races; file order in Git does not imply apply order. Forgetting hook-delete-policy blocks repeat syncs when Job names collide. Hooks that never terminate, such as interactive containers or Jobs waiting on external approval, stall syncs indefinitely. Installing an operator Deployment at wave 0 while its CRD is also wave 0 fails randomly; CRDs belong at -1 or lower until Established. Validate hook annotations in CI before ArgoCD sees the commit.

Stuck syncs usually trace to health checks, timeouts, or hooks that never finish. ArgoCD uses Lua health scripts per resource type; a Job hook must reach Completed. If a Job succeeds but ArgoCD marks it Progressing, check custom health overrides in the argocd-cm ConfigMap. Align Application timeout.reconciliation and hook Job activeDeadlineSeconds with long migrations; otherwise ArgoCD can cancel the sync while work is still running. Failed hook Jobs fail the sync unless you override health checks. Document Application sync options in your repo README so the next engineer is not debugging blind.

Application-level sync options alter semantics. ApplyOutOfSyncOnly=true skips unchanged resources but hooks still run when triggered. Replace=true forces recreate and should be used carefully with StatefulSets. PruneLast=true deletes removed resources after all waves succeed. RespectIgnoreDifferences=true honours ignore rules during health checks. Set these in the Application manifest or AppProject defaults and document them for your team. Misaligned options can make a sync look stuck or skip resources you expected to reconcile in a given wave.

Yes. In multi-source Applications, ArgoCD merges manifests from several refs and 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. Run schema validation in CI on rendered Helm or Kustomize output with tools like kubeconform or conftest before commits reach the cluster. Export ArgoCD metrics to Prometheus and alert on argocd_app_sync_total with phase Failed to catch ordering failures before users hit broken endpoints.

Share this article

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.

Quick Contact Options
Choose how you want to connect me: