#29742·argo-cd

Allow a default sync wave per resource kind via argocd-cm

Author: CharlieR-o-o-tCreated Sep 16, 2026Updated Sep 16, 2026
Labelsenhancementtriage/pendingcomponent:settingsfeature:sync-waves

Summary

Within a sync phase and wave, resources are ordered by kind. Every built-in kind in kindOrder gets a negative value, and any kind absent from the table falls through to Go's zero value - so custom resources are applied after every built-in kind. That default is deliberate and matches Helm, but it cannot be overridden anywhere except per object.

I'd like to propose resource.customizations.syncWave.<group_kind> in argocd-cm, applied only to objects that carry no sync wave of their own.

The problem

A webhook served by a cert-manager certificate. One chart, one wave:

Kind kindOrder
Service -13
Deployment -8
Certificate (CR) 0
Issuer (CR) 0

The Deployment mounts the TLS secret cert-manager writes, so the pod is created first and fails with MountVolume.SetUp failed ... secret "webhook-cert" not found. Issuer lands after the Certificate that references it, because equal kindOrder falls back to a name comparison.

Annotating both manifests fixes it, and that's the documented answer. It doesn't scale: we run a platform catalogue of ~140 charts, and for third-party charts we'd have to fork or post-process them. A chart author can't know that a consumer installs through Argo CD, and an operator has no way to state the policy centrally.

The same question recurs in #11883, #9112, #6413 — always answered with "use sync waves", which is exactly the part that doesn't scale.

Proposal

resource.customizations.syncWave.cert-manager.io_Issuer: "-3"
resource.customizations.syncWave.cert-manager.io_Certificate: "-2"

Resolution: annotation or Helm hook weight → exact key → wildcard key → wave 0. Consistent with the five customization types that already exist.

Proof of concept

Branch: https://github.com/CharlieR-o-o-t/argo-cd/tree/feat/default-sync-wave-per-resource-kind

  • syncwaves.Explicit() — tells an object asking for wave 0 from one never given a wave
  • sync.WithDefaultSyncWaves() — a SyncOpt shaped like WithHealthOverride, taking a GroupKind lookup so the engine stays free of Argo CD settings types
  • reuses the existing syncTask.waveOverride, applied before prune waves are computed so prune ordering stays the mirror of creation ordering
  • ResourceOverride.SyncWave is a string so generated deepcopy is unaffected and "unset" differs from "0"

Happy to push it into PR if that's ok.