Right, let’s talk about getting your cluster to actually do the thing you just defined in a YAML file. This is where ArgoCD stops being a fancy museum of your Git commits and starts being the engine that keeps your applications running. We call this the Sync Policy, and it’s the difference between you manually poking the deploy button and the system having a mind of its own (a blessedly obedient one, if you configure it right).

The first, and most conservative, choice is manual syncing. This is your training wheels mode, or your “this thing is so mission-critical I want a human to physically sweat over every change” mode. You push a change to Git, and nothing happens in the cluster until you go into the ArgoCD UI and hit ‘Sync’, or run argocd app sync. It’s simple, it’s safe, and it gets old really fast.

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: my-manual-app
spec:
  destination:
    server: "https://kubernetes.default.svc"
    namespace: default
  source:
    repoURL: "https://github.com/myorg/myrepo.git"
    path: kustomize-overlays/dev
    targetRevision: HEAD
  project: default
  syncPolicy:
    syncOptions: [] # This is basically the default - manual syncs.

But you didn’t install a whole continuous delivery platform to continuously not deliver, did you? Let’s automate.

Automatic Sync: Living the GitOps Dream

This is why we’re here. You tell ArgoCD to watch your Git repo, and whenever the desired state (Git) diverges from the live state (the cluster), it automatically syncs the cluster. It’s like having a brilliant, hyper-vigilant intern who never sleeps. You enable it by setting syncPolicy.automated.

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: my-auto-app
spec:
  destination:
    server: "https://kubernetes.default.svc"
    namespace: default
  source:
    repoURL: "https://github.com/myorg/myrepo.git"
    path: manifests
    targetRevision: HEAD
  project: default
  syncPolicy:
    automated: {}

That empty automated: {} block is all it takes. Now, any push to the HEAD of that branch will be automatically deployed. It’s beautiful. But we can make it smarter, and slightly more terrifying, with two incredibly powerful options: selfHeal and prune.

Self-Heal: The Cluster Fights Back

Imagine someone on your team, let’s call him “Dave,” logs into the cluster and does a kubectl delete deployment my-auto-app-frontend because “it looked like it was using a lot of CPU.” Without self-heal, your cluster is now wrong, and it stays wrong until the next Git change comes along to fix it.

With self-heal enabled (syncPolicy.automated.selfHeal: true), ArgoCD notices this deviation immediately. It sees that the live state no longer matches Git’s desired state, and it says “Not on my watch, Dave,” and redeploys that deployment. It’s actively enforcing the state defined in Git. It’s not just syncing on Git changes; it’s syncing on any drift.

syncPolicy:
  automated:
    selfHeal: true # Corrects cluster drift automatically
    prune: true    # Deletes resources removed from Git

This is the pinnacle of GitOps. Your Git repo becomes the single source of truth, and the cluster is constantly corrected to match it. It’s also why you need to lock down cluster access—otherwise, you and Dave are just going to have a very frustrating automated tug-of-war.

Prune: Cleaning Up Your Mess

Here’s the other classic “oops” scenario: you remove a Kubernetes resource from your Git repo and merge the change. With a basic automated sync, ArgoCD will happily deploy the new stuff but leaves the old, now-orphaned resource running in your cluster. Garbage.

Pruning (syncPolicy.automated.prune: true) fixes this. When ArgoCD performs a sync and realizes a resource that was previously managed exists in Git but no longer exists in the cluster, it will delete it. It’s a garbage collector for your Kubernetes objects.

This is powerful but also dangerous, which is why it’s not enabled by default. If you mess up your Kustomize/Helm setup and it suddenly renders zero objects, ArgoCD will, with pruner’s logic, try to delete your entire application. Use it, but respect it. Always preview your syncs (argocd app diff) before merging big changes.

The Sync Options You Actually Need to Know About

The syncOptions field is where you fine-tune this automated behavior. Here are the big ones:

  • CreateNamespace=true: Tells ArgoCD to create the destination namespace if it doesn’t exist. Shockingly useful.
  • RespectIgnoreDifferences=true: If you’ve told ArgoCD to ignore differences in a field (e.g., a Helm-annotated secret), this ensures that directive is respected during auto-syncs.
  • ServerSideApply=true: Switches from using kubectl apply to Server-Side Apply. Use this for large, complex applications to avoid memory issues and manage field ownership more cleanly.
syncPolicy:
  automated:
    selfHeal: true
    prune: true
  syncOptions:
  - CreateNamespace=true
  - ServerSideApply=true

So, what should you use? For development and staging? Full automated with self-heal and prune. It’s the only way to truly test the GitOps loop. For production? Many teams use automated syncs but leave self-heal disabled. This means manual intervention is required to correct drift (e.g., someone accidentally deleted something), but routine changes are still automated. It’s a nice safety valve. But if you’re brave and your permissions are tight, go full auto. Just don’t let Dave near the cluster.