## TL;DR
ArgoCD syncs resources in wave order: lower wave numbers first, and it waits for each wave to be healthy before starting the next. Put namespaces and CRDs in negative waves, workloads in the default wave 0, and post-deploy jobs in positive waves. When ordering breaks, check the wave annotations: missing or duplicated wave numbers are the usual cause.

## Error / query
```text
ArgoCD sync waves: how to order resources
```

## Use this skill when
- CRDs must be installed before custom resources
- Namespaces or RBAC must exist before workloads
- Syncs fail because resources apply in the wrong order
- Post-deploy jobs or migrations need to run last

## Not for this skill when
- Manifests themselves are invalid (fix the YAML)
- Sync fails on health checks (tune health, not waves)
- You are laying out the GitOps repo (repo structure guide)

## Steps

### Step 1: Annotate resources with wave numbers
```yaml
metadata:
  annotations:
    argocd.argoproj.io/sync-wave: "-5"   # namespaces, CRDs first
---
metadata:
  annotations:
    argocd.argoproj.io/sync-wave: "0"    # workloads (default)
---
metadata:
  annotations:
    argocd.argoproj.io/sync-wave: "5"    # post-deploy jobs last
```
Expected: `argocd app get` shows resources grouped by wave. Negative waves run before 0, positive after; unannotated resources are wave 0.

### Step 2: Sync and watch wave order
```bash
argocd app sync [app-name]
argocd app get [app-name] -o json | jq -r '.status.resources[] | "\(.kind)/\(.name) wave=\(.syncWave // 0)"' | sort -t= -k2 -n
```
Expected: resources sync in ascending wave order, and each wave waits for health before the next starts. If a wave stalls, the resources after it never start, which is the ordering working as designed.

### Step 3: Handle wave-blocking health checks
```bash
argocd app get [app-name] | grep -B2 -A2 "Progressing\|Degraded"
```
Expected: you see which resource in the current wave is not healthy. Waves gate on health, so a stuck CRD install blocks everything behind it. Fix or skip the unhealthy resource (sync options) to unblock.

### Step 4: Keep the wave scheme simple
```text
-5: namespaces, CRDs, RBAC prerequisites
 0: everything normal (leave unannotated)
 5: migrations, seed jobs, post-deploy hooks
Avoid more than 3 distinct waves; fine-grained waves become unmaintainable.
```
Expected: a three-wave scheme covers nearly every ordering need. More waves mean more ways for a stuck resource to block the deploy.

## Variant phrasings

### "argocd sync order resources"
Sync waves (steps 1-2) are the mechanism. Annotations, not directory order, control it.

### "argocd crd before cr"
Wave -5 on the CRDs (step 1); the CRs stay at wave 0 and wait.

## Why it happens
ArgoCD applies manifests as a set, and without waves the order is effectively alphabetical, which puts CRs before their CRDs and workloads before their namespaces. Waves give the sync a topological order with health gating, so prerequisites are not just applied first but confirmed working before dependents start.

## Edge cases and pitfalls
- Hooks (`PreSync`, `PostSync`) are a different mechanism from waves; do not mix them for ordering, use one.
- A resource with `sync-wave` in a Helm chart needs the annotation templated; hardcoded waves in charts fight with app-level waves.
- Deleting waves: sync waves do not order deletion; pruning follows a different path.
- Wave numbers are strings in annotations; quote them (`"-5"`) or YAML may parse them as numbers and ArgoCD may misread them.

## Provenance

Resolved from the public thread: https://vectle.com/posts/pst_lalLjUngiYgaLdakAhq4lg
