
Table of Contents
By Khimananda Oli | Last reviewed: August 2026
Deploying complex microservices or stateful applications often fails when resources apply in an unpredictable order. Sync Waves and Hooks in ArgoCD solve this by enforcing strict execution sequences and lifecycle automation directly within your GitOps workflow. Instead of relying on external CI scripts or manual intervention, you define dependencies and validation steps as metadata on your Kubernetes manifests. This guide covers the practical configuration needed to make deployments deterministic, observable, and safe.
-1, 0, 1) enforce resource application order, while Hooks trigger Jobs or Pods at specific phases like PreSync or PostSync to validate state before proceeding.How do Sync Waves and Hooks in ArgoCD enforce deployment order?
At its core, ArgoCD applies resources based on a calculated dependency graph. However, implicit dependencies—like waiting for a database schema migration before starting an API server—are invisible to the controller. Sync Waves provide an explicit integer-based ordering mechanism. Resources with lower wave numbers are applied first; ArgoCD waits for all resources in the current wave to reach a "Healthy" and "Synced" state before advancing to the next wave.
If you are new to declarative delivery, start with our primer on setting up GitOps with ArgoCD to understand the baseline reconciliation loop. Once that foundation is solid, layers of orchestration become manageable rather than magical.
Hooks complement waves by injecting ephemeral workloads at precise lifecycle points. A PreSync hook runs after the previous wave succeeds but before the current wave begins. This is where you place schema migrations, cache warming, or config validation. A PostSync hook executes only after the entire sync operation completes successfully, making it ideal for smoke tests or Slack notifications. Crucially, hooks are not part of the live application state; they are transient tasks that ArgoCD cleans up according to your deletion policy.
Annotating resources correctly
The implementation relies entirely on annotations. There is no separate CRD for ordering. Add these directly to your Deployment, Job, or custom resource metadata:
<!-- Wave Annotation -->
metadata:
annotations:
argocd.argoproj.io/sync-wave: "-1"
<!-- Hook Annotation -->
metadata:
annotations:
argocd.argoproj.io/hook: PreSync
argocd.argoproj.io/hook-delete-policy: HookSucceeded A common mistake in 2026 is assuming string sorting applies to waves. ArgoCD parses these values as integers. Wave -10 executes before wave -2, and wave 10 executes after wave 2. Always use quotes in YAML to prevent parser issues, but trust numeric comparison logic internally.
What is the difference between ArgoCD Sync Waves and Resource Hooks?
Engineers frequently conflate these two concepts because they both influence timing. Understanding the distinction prevents architectural debt. Sync Waves manage stateful resource ordering—they determine when persistent objects like Deployments, Services, and ConfigMaps enter the cluster. Resource Hooks manage transient procedural logic—they run Jobs or Pods that perform work and then typically disappear.
| Feature | Sync Waves | Resource Hooks |
|---|---|---|
| Primary Purpose | Order long-lived resources | Execute temporary tasks |
| Persistence | Remains in cluster | Deleted after completion (configurable) |
| Blocking Behavior | Blocks next wave until Healthy | Blocks sync phase until Success/Failure |
| Typical Use Case | Database → Cache → App | Migrations, Tests, Notifications |
| Annotation Key | argocd.argoproj.io/sync-wave | argocd.argoproj.io/hook |
In practice, you combine them. A typical pattern places infrastructure in Wave -1, runs a PreSync hook for migrations, deploys the application in Wave 0, and triggers a PostSync verification job. If you attempt to handle migrations purely through init containers inside your main deployment, you lose atomicity—a failed migration leaves your app in a crash loop without clear feedback. Hooks surface that failure at the sync level, halting the pipeline visibly.
Hook deletion policies matter
Without explicit cleanup, completed Jobs accumulate in your namespace, cluttering dashboards and potentially hitting quota limits. Choose wisely:
- HookSucceeded: Deletes the resource immediately after successful completion. Best for routine migrations.
- HookFailed: Retains the resource if it fails, allowing debugging. Often paired with HookSucceeded for balanced observability.
- BeforeHookCreation: Deletes any existing hook resource before creating a new one. Essential for idempotent retries during re-syncs.
How do you configure PreSync and PostSync hooks safely?
Safety in GitOps means failing fast and providing actionable signals. A poorly configured hook can hang a sync indefinitely or mask real problems. When implementing Sync Waves and Hooks in ArgoCD, treat every hook as untrusted code that must prove its own success.
Enforce hard timeouts
Never deploy a hook without activeDeadlineSeconds. A migration script hanging on a network lock should fail explicitly, not stall your release pipeline for hours. Set this field in the Job spec to cap execution time. For most schema migrations, 300 seconds is generous; for smoke tests, 60 seconds suffices.
apiVersion: batch/v1
kind: Job
metadata:
name: db-migrate
annotations:
argocd.argoproj.io/hook: PreSync
argocd.argoproj.io/hook-delete-policy: BeforeHookCreation
spec:
activeDeadlineSeconds: 300
template:
spec:
containers:
- name: migrate
image: myapp:v2.4.0
command: ["./migrate", "--up"]
restartPolicy: Never
backoffLimit: 1 Note the backoffLimit: 1. By default, Kubernetes Jobs retry failed pods. In a GitOps context, automatic retries of non-idempotent operations risk data corruption. Fail once, surface the error in the ArgoCD UI, and let the engineer decide whether to fix the code or revert the commit.
Validate health, not just existence
For resources in Sync Waves, ArgoCD uses built-in health assessors. Custom resources may lack these. If your Wave -1 includes a custom operator CRD, ArgoCD might consider it "Healthy" the moment it exists, even if the underlying controller hasn't initialized. Define custom health checks in the ArgoCD ConfigMap or use a Lua script to verify actual readiness before allowing Wave 0 to proceed. This depth separates production-grade GitOps from toy setups.
When should you use Sync Waves versus native Kubernetes dependencies?
Kubernetes already provides some ordering primitives: init containers, readiness probes, and owner references. Overusing Sync Waves creates artificial coupling that fights the platform's eventual consistency model. Reserve explicit waves for cross-resource dependencies that Kubernetes cannot express natively.
Use native mechanisms when possible
- Init Containers: Perfect for waiting on a service endpoint or generating config files needed by the main container. Keeps dependency localized to the pod.
- Readiness Probes: Prevents traffic routing until the app is truly ready. Handles slow startups better than static wave delays.
- Operators: Complex setup logic belongs in a controller, not a sequence of YAML files. See our guide on extending the API with operators for patterns that reduce wave complexity.
Reserve waves for true orchestration gaps
Use Sync Waves and Hooks in ArgoCD specifically when:
- You need to provision shared infrastructure (namespaces, quotas, RBAC) before tenant workloads.
- External systems require sequential initialization (e.g., primary DB → replica → connection pooler).
- Compliance mandates verified state transitions with audit trails between phases.
- Cross-cutting concerns like certificate issuance must complete before ingress creation.
If you find yourself adding waves to every single microservice, reconsider your architecture. Tight coupling in deployment often reflects tight coupling in design. Strive for independent deployability; use waves as guardrails, not crutches.
How do you debug failed Sync Waves and Hooks in ArgoCD?
When a sync stalls, the ArgoCD UI shows the pending wave but rarely explains why. Effective debugging requires correlating Git state, Argo events, and cluster reality.
Check hook logs first
For failed PreSync/PostSync jobs, click the resource in the ArgoCD UI and view logs. Most failures stem from missing secrets, incorrect image tags, or timeout breaches. Since hooks are ephemeral, logs vanish after deletion unless you've configured retention. During development, temporarily set hook-delete-policy: HookFailed to inspect failed pods manually.
Verify health assessor behavior
If a wave hangs despite all pods running, the health check is likely the bottleneck. Run argocd app get <app-name> --refresh to force reassessment. Check the application controller logs for Lua script errors or missing CRD definitions. In multi-cluster setups, ensure the destination cluster has matching CRD versions—a subtle mismatch causes perpetual "Progressing" states.
Audit annotation syntax
Typos in annotations silently disable orchestration. argocd.argoproj.io/sync-wave: "-1" works; sync-wave: "-1" does nothing. Validate manifests locally using argocd admin app diff or CI linting tools before pushing. For teams managing dozens of services, consider a Kustomize transformer or Helm helper template to inject wave annotations consistently, reducing human error. This aligns with practices discussed in template-free Kubernetes config management.
Implementing Reliable Sync Waves and Hooks in ArgoCD
Mastering Sync Waves and Hooks in ArgoCD transforms chaotic deployments into predictable, auditable pipelines. Start small: add a single PreSync hook for database migrations before introducing complex wave topologies. Measure sync duration and failure rates to validate improvements. Remember that orchestration adds cognitive overhead—document your wave strategy in the repository README so new team members understand the sequence. For teams scaling GitOps across multiple environments, consider exploring blue-green and canary strategies alongside waves for progressive delivery. If your deployment orchestration needs architectural review or your team is struggling with flaky syncs, reach out for hands-on support to build resilient GitOps workflows that survive production pressure.