Skip to main content
RunBook Academy

Git, CI/CD & GitOpsLXXIX · Sync StrategiesSyncStrategies

Prune and the blast radius — what prune deletes and the safety discipline

Advanced⏱ ~26 mingitargocd

What you'll learn

  • Describe what prune deletes and what it does not
  • Identify the failure mode an unintended prune produces in production
  • Configure prune per-Application using --auto-prune and the Prune=false sync option
  • Apply the safety discipline - namespace backup, ownership audit, dry-run - before enabling prune

Prerequisites

Verified against Git 2.55.x teaching target; 2.40+ minimum · GitHub Actions continuous service; Aug 2026 documentation baseline · Argo CD v3.5.x teaching target; v3.0+ minimum · Flux v2.9.x · Sigstore Cosign v3.1.x · SLSA v1.2 · OCI Distribution Specification v1.1 · Git LFS v3.7.1 · Kubernetes (cross-course target) 1.36.x

Not yet marked complete on this device.

Prune is the option that makes “delete this from the cluster” a Git commit rather than a kubectl command. The commit lands, the controller reconciles, the resource is deleted from the cluster. The change is auditable; the deletion is reproducible. But the same property that makes prune an audit trail - it deletes unconditionally on a diff that removes the resource - is what makes an unintended prune catastrophic.

What prune actually deletes

Prune is enabled with spec.syncPolicy.automated.prune (the --auto-prune flag) in Argo CD or spec.prune: true in Flux. The controller’s contract:

  • Prune deletes resources the controller owns. A resource present in the cluster but absent from the previous apply inventory is a candidate for deletion.
  • Prune does not delete resources the controller does not own. A kubectl apply from an operator, a Helm install from another chart, a resource the controller has never seen are not pruned. Argo CD inventories its own resources by metadata; Flux inventories by the kustomize.toolkit.fluxcd.io/name label.
  • Prune follows the chart’s source. A manifest that is removed from the chart, or a values entry that resolves to an empty set, results in a prune of the corresponding resource.
argocd app set payment-api \
  --auto-prune

The --auto-prune flag enables pruning when the chart loses a manifest. The per-sync alternative is argocd app sync payment-api --prune, which prunes on one manual sync; individual resources opt out with the argocd.argoproj.io/sync-options: Prune=false annotation.

The blast radius of an unintended prune

A chart that loses a manifest because the manifest was moved to a different chart, because the manifest was renamed, because the values-merge produced an empty list - will, under prune: true, delete the corresponding resource from the cluster. The chart’s bug becomes the cluster’s outage.

flowchart LR
    M["Manifest removed from chart"] --> R["Render omits resource"]
    R --> D["Diff shows resource missing"]
    D --> P{"prune=true?"}
    P -->|yes| X["DELETE resource from cluster"]
    P -->|no| W["Resource stays in cluster"]
    X --> C["Cluster state matches Git"]
    W --> C

The right side of the diagram is the production-grade failure mode: the resource stays, the cluster drifts from Git, and the Kustomization reports Ready=True anyway because its apply contract only covers what is in the new build. The left side is the catastrophic failure mode: the resource is deleted.

The safety discipline

Three rules that make prune survivable:

  1. Per-Application configuration. Prune is enabled per Application, not per cluster. A workload whose chart shares resources with another workload (an admission webhook shared with another Application, a ConfigMap referenced by both) must not have prune enabled until the ownership is clear.
  2. Namespace backup before first prune. The first time a chart with prune enabled deploys, the team must be able to restore the namespace if the prune deletes something unexpected. The backup is the recovery path; the audit is the prevention.
  3. Dry-run before prune. Argo CD’s argocd app diff payment-api shows what the next sync will do. A team that enables prune should diff the next sync and confirm the deletions match the team’s intent.

The Prune=false sync option override

The escape hatch when an Application - or a single resource - must not be pruned, even with prune otherwise enabled:

argocd app set payment-api \
  --sync-option Prune=false

This sets the Prune=false sync option on the Application’s standing configuration. Syncs stop deleting its resources; prune candidates are reported as out-of-sync instead. Remove the option with argocd app set payment-api --sync-option '!Prune=false' (the ! prefix removes the option) to resume pruning; the opt-out is standing and reversible, not permanent. For one resource, the same opt-out is the argocd.argoproj.io/sync-options: Prune=false annotation on the resource itself.

The same effect is achieved in Flux with spec.prune: false on the Kustomization; in both controllers the opt-out is a standing, reversible setting.

Prune in Flux versus Argo CD

The two controllers implement prune differently:

  • Argo CD prunes any resource in the Application’s inventory that is not in the new render. The app-level Prune=false sync option and the per-resource Prune=false annotation tune the boundary.
  • Flux prunes only resources it has the kustomize.toolkit.fluxcd.io/name label on. A resource that was never applied by the controller is not pruned; a resource that was applied by the controller and is now absent from the build is pruned.

The Flux boundary is tighter by default. Argo CD’s boundary is broader by default and tunable with the app-level sync option and the per-resource annotation.

Production discipline

  1. Prune is enabled per Application after an ownership audit. The team must know what the controller will delete before the first prune-enabled sync.
  2. Prune is paired with a namespace backup. The first prune-enabled sync is the highest-risk deploy the team will ever do for that Application.
  3. Prune is paired with branch protection. A typo in the chart must not auto-prune before review.
  4. Prune=false sync option is the standing opt-out. Set it per-Application with argocd app set --sync-option Prune=false, or per-resource with the argocd.argoproj.io/sync-options: Prune=false annotation.

Cross-course references

  • Git, CI/CD & GitOps for Infrastructure Engineers - Part LXXVII-04 (Sync policies and windows) covers the policy frame this lesson deepens; Part LXXVI (GitOps Repo Architecture) is where the chart structure that prune operates on lives.
  • Kubernetes for Production Sysadmins - Part VII (Workloads) is the resource class prune operates on; Part XVI (Operators and Controllers) covers the reconcile loop.

Quiz

Knowledge check · 4 questions

  1. Q1. A team enables prune on an Application whose chart shares a ConfigMap with another Application. What is the most likely production failure?

  2. Q2. Prune in Flux and Argo CD have the same default behaviour: both delete any cluster resource absent from the new render.

  3. Q3. Name the three rules of the prune safety discipline and explain why each is necessary.

  4. Q4. Diagnose why a critical ConfigMap was deleted and recommend the prevention.

    A team runs an Application with prune enabled in production. A developer refactors a Helm chart and removes a ConfigMap that is also consumed by an admission controller in the same namespace. The PR is merged; the next automated sync prunes the ConfigMap. The admission controller fails to start its webhook server because the ConfigMap is missing, and production admission breaks. The team has no namespace backup. The ConfigMap is restored from an outdated commit that did not have the admission controller's CA bundle.

Passing score: 75%. Answers are checked in this browser.