Sync Waves and Hooks in ArgoCD

Khimananda Oli 8 min read Virtualization
Sync Waves and Hooks in ArgoCD

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.

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.

Wave -1Namespace/CRDsPreSync HookDB Migration JobWave 0Backend/APIPostSync HookSmoke Test / NotifyArgoCD advances only after each phase reports Healthy & Synced
Sync Waves and Hooks in ArgoCD create a deterministic left-to-right execution pipeline preventing race conditions.

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.

FeatureSync WavesResource Hooks
Primary PurposeOrder long-lived resourcesExecute temporary tasks
PersistenceRemains in clusterDeleted after completion (configurable)
Blocking BehaviorBlocks next wave until HealthyBlocks sync phase until Success/Failure
Typical Use CaseDatabase → Cache → AppMigrations, Tests, Notifications
Annotation Keyargocd.argoproj.io/sync-waveargocd.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.

Hook TriggeredActiveDeadlineSeconds?Exit Code == 0?Proceed SyncFail & HaltTimeout Error
Safety decision tree for Sync Waves and Hooks in ArgoCD ensuring timeouts and exit codes gate progression.

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:

  1. You need to provision shared infrastructure (namespaces, quotas, RBAC) before tenant workloads.
  2. External systems require sequential initialization (e.g., primary DB → replica → connection pooler).
  3. Compliance mandates verified state transitions with audit trails between phases.
  4. 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.

Without OrchestrationApp StartsDB MigratesCache ReadyRace Conditions & CrashLoopsWith Sync Waves + HooksWave -1: InfraPreSync: MigrateWave 0: AppDeterministic & Auditable
Side-by-side impact of adopting Sync Waves and Hooks in ArgoCD versus unstructured applies.

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.

Frequently Asked Questions

Sync Waves define the execution order of Kubernetes resources during an ArgoCD sync operation using metadata annotations. Resources with lower wave numbers apply first, allowing dependencies like namespaces or CRDs to exist before dependent workloads deploy in 2026 environments.

Add the annotation argocd.argoproj.io/sync-wave with an integer value to your resource metadata. Negative values execute first, zero is default, and positive values run later. ArgoCD sorts all resources by this value before applying them sequentially during synchronization.

Hooks are special resources annotated to run at specific sync phases like PreSync, Sync, or PostSync. They execute tasks such as database migrations or health checks outside the main resource application flow, ensuring operational steps occur at precise deployment stages.

Yes, combine them for complex orchestration. Use waves to order standard resources and hooks for phase-specific actions within those waves. A PreSync hook in wave -1 runs before wave 0 resources, enabling granular control over deployment sequencing.

Verify the annotation key is exactly argocd.argoproj.io/sync-wave and the value is a valid integer string. Check that resources belong to the same Application and sync policy. Misconfigured annotations or cross-application references break wave ordering silently.

Inspect the hook pod logs via kubectl or ArgoCD UI. Ensure the hook resource has the correct argocd.argoproj.io/hook annotation and deletion policy. Failed hooks block subsequent waves; check exit codes and resource quotas that may prevent hook pod scheduling.

The sync operation marks as degraded but applied resources remain. Configure argocd.argoproj.io/hook-delete-policy to OnHookSucceeded or HookFailed to manage cleanup. Retrying the sync reruns the failed PostSync hook without reapplying successful earlier waves unless manually pruned.

Yes, add wave annotations directly in Helm templates or use post-renderers. ArgoCD processes rendered manifests and respects wave annotations regardless of source. Ensure helm template outputs include the exact annotation key for proper ordering during server-side apply operations.

Use selective sync in ArgoCD UI or CLI to target specific resources. Alternatively, temporarily remove the sync-wave annotation from skipped resources. There is no native wave-skip flag; manual filtering or annotation modification remains the standard approach in 2026.

Sync Waves are ArgoCD runtime constructs controlling apply order, while Kustomize determines manifest generation sequence. Waves operate post-rendering during cluster reconciliation. Kustomize cannot enforce runtime dependency ordering across API calls; only ArgoCD Sync Waves guarantee execution sequence during actual syncs.

Yes, each wave waits for prior wave completion and health checks. Ten sequential waves add latency versus parallel apply. Minimize wave count by grouping independent resources. Use health assessments wisely; excessive readiness gates between waves compound total deployment time unnecessarily.

No, Sync Waves apply per Application within a single cluster context. For multi-cluster ordering, use ApplicationSets with wave annotations on generated Applications or external orchestration tools like Crossplane. Each cluster sync operates independently; cross-cluster wave coordination requires higher-level workflow management.

ArgoCD lacks per-wave timeout configuration. Set global sync timeout via application.spec.syncPolicy.automated.selfHealTimeout or controller flags. Long-running waves risk hitting global limits. Break large waves into smaller units or optimize resource readiness probes to prevent unnecessary timeout failures during complex deployments.

Yes, annotations persist on live cluster resources. They do not affect runtime behavior outside ArgoCD. Remove them via Kustomize patches or Helm conditionals if clean manifests are required. ArgoCD reads these annotations only during sync planning, not during steady-state reconciliation cycles.

Hooks run with RBAC permissions granted to ArgoCD service accounts. Malicious or misconfigured hooks can modify cluster state outside intended scope. Restrict hook service accounts, validate hook images via admission controllers, and audit hook execution logs. Never grant cluster-admin to hook runners in production 2026 environments.