Controlling Resource Creation Order in Argo CD with Sync Waves and Auto-Sync
Argo CD applies resources in parallel during auto-sync unless you use sync-wave annotations. Learn how to stage namespace, deployment, and service creation with a worked example.
20 Apr 2026, 12:17 UTC

The ordering problem during automatic sync
When Argo CD detects that a cluster differs from Git and spec.syncPolicy.automated is set, it pushes every resource in the Application at once. Without extra guidance, a Deployment can be submitted before the Namespace that should contain it, or a Custom Resource can appear before its CustomResourceDefinition. The sync then fails, or the workload starts in a broken state.
The reliable fix is to tag each resource with the argocd.argoproj.io/sync-wave annotation. Argo CD reads these tags, sorts resources by their numeric wave value, and applies them from the lowest wave to the highest. Resources that share a wave are processed together, giving you deterministic staging inside a single automatic sync.
How Argo CD evaluates sync waves
Auto-sync is enabled per Application under spec.syncPolicy.automated. In a standard installation this is an object that may include fields such as prune or selfHeal; the exact shape depends on your Argo CD version, so confirm the available fields against the Application CRD in your cluster.
Once automatic sync is active, Argo CD collects every manifest in the Application, reads the argocd.argoproj.io/sync-wave annotation, and sorts the list. A resource with wave "0" is applied before wave "1". If the annotation is absent, Argo CD treats the resource as wave 0. Negative numbers are valid and run before zero, but they are easy to overlook.
Worked example: namespace, deployment, and service
The following manifests show a minimal Application that creates a Namespace, then a Deployment, then a Service. Each dependent resource sits in a later wave so the namespace exists before anything is placed inside it.
Save the Application manifest as application.yaml:
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: web-stack
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/example/web-stack.git
targetRevision: HEAD
path: manifests
destination:
server: https://kubernetes.default.svc
namespace: web
syncPolicy:
automated: {}
In the manifests/ directory of that repository, add the Namespace in wave 0:
apiVersion: v1
kind: Namespace
metadata:
name: web
annotations:
argocd.argoproj.io/sync-wave: "0"
Add the Deployment in wave 1:
apiVersion: apps/v1
kind: Deployment
metadata:
name: api
namespace: web
annotations:
argocd.argoproj.io/sync-wave: "1"
spec:
replicas: 1
selector:
matchLabels:
app: api
template:
metadata:
labels:
app: api
spec:
containers:
- name: api
image: nginx:stable
ports:
- containerPort: 80
Add the Service in wave 2:
apiVersion: v1
kind: Service
metadata:
name: api
namespace: web
annotations:
argocd.argoproj.io/sync-wave: "2"
spec:
selector:
app: api
ports:
- port: 80
targetPort: 80
Apply the Application manifest to the cluster that runs Argo CD. You need permission to create Applications in the argocd namespace. Applying this manifest changes cluster state, so verify the repository URL, path, and destination namespace before syncing. Argo CD will clone the repository, detect the three resources, and sync them in ascending wave order.
What sync waves do not guarantee
Sync waves control the order in which Argo CD submits manifests to the Kubernetes API. They do not wait for a resource to become ready. A Deployment in wave 1 is submitted after the Namespace in wave 0, but Argo CD does not pause until the namespace is fully active or until pods are running. If your workload needs a database to accept connections before it starts, waves alone are insufficient; you need readiness probes, init containers, or an operator that handles that dependency.
Resource types that are reconciled by other controllers can also behave unexpectedly. Some operators and Helm charts manage their own ordering through hooks or finalizers, and they may override or ignore the sync-wave annotation. Cluster-scoped resources and CustomResourceDefinitions can be annotated, but verify that your specific controller respects the ordering rather than assuming it.
Common mistakes that break wave ordering
- Forgetting the annotation on a dependent resource. If a ConfigMap is required by a Deployment but lacks a wave tag, it defaults to wave
0and may be created after the Deployment has already started. - Reusing the same wave for unrelated resources. Two resources in wave
1are applied in parallel. If one depends on the other, the sync can fail intermittently. Give each dependency its own wave when order matters. - Creating circular dependencies. If resource A waits for wave
1and resource B in wave1waits for A, the sync cannot converge. Argo CD will report a failure, and the Application will remain out of sync. - Over-scaling wave numbers. Jumping from wave
1to wave1000leaves no room for future resources and makes the spec harder to read. Small, sequential integers are easier to maintain. - Relying on negative waves without documentation. Wave
"-1"is valid, but new team members may not expect it. Prefer starting at0unless you have a specific pre-flight resource.
Verifying the applied order
After pushing the manifests, open the Argo CD UI and inspect the Application's sync status. The operation view groups resources by wave and shows the sequence. For a command-line check, query the creation timestamps of the resulting objects. Run the following from any machine with kubectl access to the target cluster; you need read permission on the web namespace:
kubectl get namespace web -o jsonpath='{.metadata.creationTimestamp}{"\n"}'
kubectl get deployment api -n web -o jsonpath='{.metadata.creationTimestamp}{"\n"}'
kubectl get service api -n web -o jsonpath='{.metadata.creationTimestamp}{"\n"}'
The Namespace timestamp should be earlier than the Deployment timestamp, which should be earlier than the Service timestamp. If the Deployment appears before the Namespace, the annotation is missing or malformed. Check that the value is quoted as a string, for example "1", because an unquoted number can be parsed differently by the annotation validator.
You can also review the application controller logs for sync-wave grouping. Run kubectl logs -n argocd deployment/argocd-application-controller (or the equivalent controller deployment in your installation) and look for entries that reference the Application name and wave numbers. Exact log wording varies by version, so treat the timestamps on the live objects as the authoritative check.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.