Automating deployments: manual versus automated sync strategies, options such as prune and self-healing, execution order through sync phases and waves, and how ArgoCD assesses application health.

In episode 6 you felt the first joy of GitOps — but maybe also the complexity: every change had to be synced manually. Don't worry, that's by design: ArgoCD separates detection (always automatic) from application (can be automatic or manual). This decision has a huge impact on security and team workflow.
This episode covers sync strategies and policies in depth: when to choose manual vs automated, the dangers and benefits of auto-prune and self-healing, how sync options change the way resources are applied, how sync phases and waves control execution order, and how health assessment determines an application's state.
As in episode 6: ArgoCD keeps detecting Git changes and flags OutOfSync, but waits for approval (argocd app sync api or the button in the UI). Suitable for production with human approval.
ArgoCD immediately applies every detected change:
argocd app set api --sync-policy automatedor declaratively:
spec:
syncPolicy:
automated:
prune: false
selfHeal: falseBy default ArgoCD does not delete resources that disappear from Git — this protects against accidental mass deletion. With prune: true, resources no longer present in Git are also deleted:
argocd app set api --sync-policy automated --auto-prune --self-healWithout self-heal, if someone manually changes a Deployment (kubectl scale deployment api --replicas=10), ArgoCD will flag OutOfSync but won't revert the change. With selfHeal: true, ArgoCD restores resources to the Git state automatically.
Warning
The automated + prune + self-heal combination is the most "aggressive" mode. It's only safe if your Git repository is well organized and every change goes through a PR. In a busy environment, enable this feature gradually and monitor the ArgoCD events.
Sync windows limit when auto-sync is allowed to run — for example a maintenance window or a freeze period:
apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata:
name: default
spec:
syncWindows:
- kind: deny
schedule: "0 22 * * *"
duration: "8h"
applications:
- "*-prod"The code above forbids auto-sync for all applications ending in -prod starting at 22:00 for 8 hours. Manual sync can still be run by those with permission.
Sync options are fine-grained adjustments to how resources are applied. Some of the most commonly used:
| Option | Effect |
|---|---|
Prune=true | Delete resources that are not in Git |
Replace=true | Replace the resource with DELETE + CREATE (instead of update) |
ApplyOutOfSyncOnly=true | Apply only the resources that differ |
ServerSideApply=true | Use server-side apply (field ownership) |
RespectIgnoreDifferences=true | Respect the ignore differences list while applying |
Force=true | Bypass resource conflicts (e.g. immutability) |
Example usage:
argocd app set api \
--sync-option ServerSideApply=true \
--sync-option Force=trueTip
ApplyOutOfSyncOnly=true speeds up large syncs because ArgoCD only touches the resources that differ, not the whole manifest list.
Every sync goes through sequential phases, and in between the phases ArgoCD runs resource hooks (e.g. a Job). The main phases:
| Phase | Order | Use case |
|---|---|---|
PreSync | 1 | Database migration, backup, validation |
Sync | 2 | Applying the main resources |
PostSync | 3 | Smoke test, success notification |
SyncFail | 3 (on failure) | Rollback, failure notification |
Skip | - | Skip a particular phase |
Hooks are marked through annotations on the resource:
apiVersion: batch/v1
kind: Job
metadata:
name: db-migrate
namespace: production
annotations:
argocd.argoproj.io/hook: PreSync
spec:
template:
spec:
restartPolicy: Never
containers:
- name: migrate
image: ghcr.io/arman/api:v1.0.0
command: ["node", "migrate.js"]ArgoCD holds the next phase until the hook finishes successfully.
Phases organize the stages, sync waves organize the order within one phase. Every resource gets an annotation weight (default 0), executed from smallest to largest:
metadata:
annotations:
argocd.argoproj.io/sync-wave: "0" # namespace, config
---
metadata:
annotations:
argocd.argoproj.io/sync-wave: "1" # ConfigMap, Secret, database
---
metadata:
annotations:
argocd.argoproj.io/sync-wave: "2" # Deployment, ServiceResources in the same wave are applied in parallel; across waves they're applied in sequence. A common pattern: 0 for Namespace/ConfigMap, 1 for database/stateful, 2 for the application.
After the sync, ArgoCD assesses the health of the resources:
Ready.CrashLoopBackOff, replicas not ready.argocd app get api
Project: default, Server: https://kubernetes.default.svc
Health Status: Healthy
Sync Status: SyncedNote
ArgoCD's health checks follow built-in rules per resource (Deployment, StatefulSet, etc.) and can be customized via argocd.argoproj.io/health-check annotations for your own CRDs.
You now control how and when changes are applied:
prune and self-heal keep the cluster always following Git, with risks you need to understand.Prune, ServerSideApply, Force change the way apply works.All the examples so far use plain manifests. In episode 8 we'll manage much more realistic configuration: using Helm and Kustomize as the Application source — charts, values files, Helm hooks, Kustomize bases and overlays, and even combinations of the two. See you there!