Ignoring expected differences in Argo CD starts with knowing which fields drift legitimately
An application stays OutOfSync after a successful sync because something other than Git changes a field after Argo CD applies it. A mutating webhook may inject a sidecar, a controller may fill in a default, or Kubernetes may normalize a value. The scoped mechanism for this is ignoreDifferences, which tells Argo CD to skip specific fields during comparison. It is the right tool when the change is expected, owned by another controller, and harmless to the desired state. It is the wrong tool when your manifest is simply incomplete or wrong, because the fix belongs in Git. Before adding any rule, confirm which actor writes the field by checking the live object's managedFields and the controller's documentation.
The Argo CD diffing customization guide describes two levels. At application level, ignoreDifferences in the Application spec accepts jsonPointers, jqPathExpressions and managedFieldsManagers, each scoped by group, kind, name and namespace so a rule cannot quietly apply to unrelated resources. At system level, rules live in the argocd-cm ConfigMap under resource.customizations.ignoreDifferences.<group>_<Kind> (or the .all variant), and resource.compareoptions governs how status fields and aggregated ClusterRole rules are compared. Use application rules for one team's exceptions and system rules for patterns every cluster shares, such as a field a common operator always rewrites.
The goal is narrow exclusion, not silencing the application. Each rule should name one field, one resource kind and one known writer, and it should be reviewed when that writer changes. Broad rules, such as ignoring an entire spec or every field a manager touches, hide real drift from the diff view and from the people who rely on it. Ask your team to record the reason for each rule in the Application manifest or a comment in the system configuration, and to test that a deliberate change to the ignored field is still visible through other means, such as your admission policies or a periodic audit of live objects.
Choosing between application-level and system-wide rules
An application-level rule sits in the Application manifest under spec.ignoreDifferences. It can match a resource by group, kind, name and namespace, and it can use JSON pointers, jq path expressions or managed fields managers. A system-wide rule sits in the argocd-cm ConfigMap under resource.customizations.ignoreDifferences.<group>_<Kind> for one resource type, or under the .all variant for every resource. The application rule travels with the application's Git source. The system rule lives in the cluster configuration of the Argo CD installation.
- Application rule scope: Only the named application and the resources it matches are affected.
- System rule scope: Every application in that Argo CD instance that manages a matching resource is affected.
- Name and namespace matching: Application rules can narrow to one resource, which keeps the exception visible in the Git history of that app.
- Git visibility: Application rules are reviewed through the same merge process as the workload they change.
- Configuration location: System rules are changed by whoever can edit
argocd-cm, which is usually a small platform group.
Before choosing a location, list each difference you intend to ignore and note which resources produce it. Confirm the exact field names and matching options against the diffing guide for your Argo CD version.
Application rules are usually owned by the team that owns the workload, because they know why a field changes at runtime, such as a replica count set by an autoscaler. System rules are usually owned by the platform team, because they affect every team that uses the instance. Treating the two as interchangeable blurs accountability: a platform change can silently alter the sync result for an application team that never reviewed it.
- Application owners: Decide and document exceptions for their own workloads.
- Platform team: Maintains
argocd-cm, reviews any.allrule and publishes the org-wide defaults. - Security or audit reviewers: Should be able to see every ignore rule, at the application and system level, in one place.
- Change approval: Agree in advance which kinds of rule need platform approval and which the application team can merge alone.
- Review cadence: Set how often exceptions are revisited, especially after controller or Kubernetes upgrades.
Ask your team to write down who approves each rule type before the first exception is added, so the process exists before there is pressure to bypass it.
A platform team can set defaults for resource types that differ the same way across the organization, such as a field a common controller always rewrites. Defining these once in argocd-cm avoids repeating the same application rule in hundreds of manifests. Defaults work best when they are narrow: one group and kind, with the specific JSON pointer or jq path that the platform team has verified.
- Start with known controllers: Add rules only for differences that have been observed and explained.
- Keep kinds specific: Use
<group>_<Kind>entries rather than.allwhenever the difference is tied to one resource type. - Document each default: Record the reason in the change, the affected kind and the version it was tested against.
- Allow local override: Application teams should still be able to add narrower exceptions where a workload needs one.
- Test before rollout: Apply the change in a non-production instance and check the diff output for affected applications.
Ask the platform team to list every system rule in use and the reason for each, and confirm which ones were tested against your current Argo CD release.
A rule under .all applies to every resource Argo CD manages, including workloads that have no known reason to differ. If the ignored path is a field that a team later changes on purpose, such as a container image, a security context or an annotation that controls network policy, that change will not appear as drift. The sync status can show green while the live state no longer matches Git. This is the main way ignore rules hide real problems.
- Silent drift: An
.allrule on a common field, such as/metadata/annotations, can conceal manual edits across unrelated apps. - Wide blast radius: A single rule change can alter sync results for every application in the instance.
- Hidden policy changes: Security-relevant fields can be excluded without anyone deciding that they should be.
- Harder audits: Evidence that Git and the cluster match becomes weaker when exclusions are broad.
- Reduced detection: Teams may stop investigating OutOfSync states because they assume the diff is expected.
An illustrative check: pick one workload that should never be edited by hand, make a small change to a non-ignored field, and confirm that Argo CD still reports OutOfSync. Confirm the expected behavior in your own environment before relying on any rule.
Which ignore mechanism fits which kind of difference
This table compares the five mechanisms named in the Argo CD diffing guide, showing the symptom each one addresses, when it fits, its main trade-off and whether it applies to one application or the whole system. Use it to pick the narrowest mechanism that covers the difference, because a broad rule can hide drift you need to see.
| Mechanism | Typical symptom | When it fits and main trade-off | Scope |
|---|---|---|---|
| jsonPointers | A single field, such as a replica count set by an autoscaler, differs from Git on every comparison | Fits one known field on one resource. Trade-off: the path is fixed, so a renamed or moved field silently stops being ignored. | Application (per resource, matched by group, kind, name and namespace) |
| jqPathExpressions | A value with a variable shape, such as a list entry or a conditional field, differs across resources | Fits differences that need a query, such as selecting list items by name. Trade-off: expressions are harder to review and test, and a broad query can mask real changes. | Application (per resource, matched by group, kind, name and namespace) |
| managedFieldsManagers | Fields are changed by a controller or tool, such as a mutating webhook or another operator, that owns them | Fits differences introduced by a named field manager, so the rule follows the actor. Trade-off: anything that manager writes is ignored, including changes you want to review. | Application (per resource) |
| resource.compareoptions (status field) | Status or runtime fields show as OutOfSync because the controller compares observed state with Git | Fits clusters where status is written by controllers and should not drive sync. Trade-off: applies to every resource of the matched type across the cluster, so review its effect on each kind it covers. | System (argocd-cm) |
| Aggregated ClusterRole rules | Rules of an aggregated ClusterRole are reported as drift after controllers add rules automatically | Fits roles that aggregate rules from labels by design. Trade-off: rule changes from any source are excluded from comparison, so confirm which role labels you rely on before ignoring. | System (argocd-cm, via resource.compareoptions) |
How to configure ignoreDifferences without hiding real drift
This sequence turns a noisy, expected diff into a narrow ignore rule that scopes to one application and one field, and it proves afterward that the rule still lets real changes surface as OutOfSync.
Confirm the diff with the CLI or UI
Run argocd app diff for the affected application, or open the resource in the Argo CD UI, and record each resource and field that shows as different from Git. Do this before touching any configuration, so the rule targets a difference you have actually seen. Done means you have a written list of the resource kind, name, namespace and the exact fields in the diff, and you can reproduce the OutOfSync status on demand.
Identify the field path and the actor
For each differing field, find the JSON path in the live object and determine what writes it: a mutating admission webhook, a controller, an operator, an autoscaler, or a person running kubectl. Check the object's managedFields to see which manager owns the value. Done means every difference has a named owner and a single JSON pointer or path that describes it, and you can explain why Git does not carry that value.
Choose the narrowest mechanism
Pick the smallest rule that matches the actor. A jsonPointers entry suits one known field, a jqPathExpressions entry suits a value that moves within a list, and managedFieldsManagers suits a field owned entirely by one controller. Keep system-wide rules in argocd-cm for resource types that many applications share, and keep per-application rules in the Application spec. Done means you can state why the other mechanisms would ignore more than the drift you have confirmed.
Write the rule with name and namespace scope
Add the ignoreDifferences block to the Application spec with the group, kind, name and namespace of the target resource, plus the chosen field path. Scope the name and namespace so the rule matches only the intended object, and avoid wildcard matches unless you have confirmed they are needed. For system-wide rules, follow the argocd-cm key format from the diffing guide. Done means the manifest is committed to Git and reviewed like any other change, and the scope fields name a single resource or a set you can list.
Sync and confirm the expected field is ignored
Sync the application and rerun argocd app diff or check the UI. The application should move to Synced, and the field you configured should no longer appear in the diff. If it still shows, compare the rule's path or scope against the resource identity printed in the diff, because a small mismatch is the most common cause. Done means the application reports Synced and the ignored field appears nowhere in the diff output.
Test that real drift still shows OutOfSync
Make a deliberate, reversible change to a field that is not in the ignore rule, such as an image tag or a replica count on a non-ignored resource, either in a non-production environment or through a short-lived test change. The application should show OutOfSync with that field in the diff. Then revert the change and confirm the application returns to Synced. Done means you have evidence that the rule hides only the expected field and not the change you care about.
Record the rule and plan the rollback
Document the rule, the actor that causes the difference, the owner who accepts it, and the test you ran. To roll back, remove the ignoreDifferences entry from the Application or argocd-cm in Git, sync, and confirm the diff returns as expected. Revisit the rule whenever the owning controller or webhook changes version. Done means the change record names the owner and the rollback steps, and the rule can be reverted with a single Git change.
How Argo CD compares live state after ignore rules apply
Argo CD computes a diff between desired state and live state for each resource it manages. Desired state is the manifest rendered from the Git source (or other configured source) at the target revision. Live state is the object currently stored in the destination cluster. The comparison runs field by field, and any difference that is not excluded marks the resource as OutOfSync in the application. Ignore rules change the outcome of that comparison, not the content of either side: an application-level ignoreDifferences entry, or a system-wide rule in argocd-cm, tells the controller which paths to drop before the two documents are compared. Confirm the exact matching behavior for your Argo CD version in the diffing guide, since it determines whether a rule matches the fields you intend and nothing else.
Removing a path from the comparison does not stop the cluster from writing to it. A field excluded by jsonPointers, jqPathExpressions or managedFieldsManagers is still set, changed and owned by whatever controller, webhook or admission process touches it. Argo CD simply stops reporting that field as drift. This is why an ignore rule is only safe when someone can say which component writes the field and why that write is expected. Before adding a rule, run a diff on the live object, identify the field manager or mutating component, and record the reason in the rule's commit message or annotation. Review those rules when the controller or webhook changes, because a rule written for one owner can silently cover a different field after an upgrade.
Because the ignored path stays unmanaged by Git, a broad rule is the main way to hide real drift. Scope rules to the narrowest group, kind, name and namespace, and prefer a single JSON pointer over a wildcard that covers a whole subtree. Test each rule against a deliberately changed field before you rely on it, so you know a genuine change still shows as OutOfSync. Ask your team to document which fields are excluded in each application, and include those exclusions in the change review that covers Argo CD configuration. An ignore list that nobody can explain is a configuration risk, even when the application reports Synced.
Risks of over-broad ignore rules and how to contain them
An ignore rule tells Argo CD to stop reporting a difference, so it also tells everyone else to stop looking. The cards below cover the places where a narrow exception quietly grows into hidden drift, and the review habits and access controls that keep each rule scoped to the field it was written for.
Hidden drift on security-relevant fields
A rule written to silence a replica count or an annotation can also silence a change to a securityContext, a service account, or an image reference if the path is too loose. Argo CD will then show the application as Synced while the live object runs something Git never approved. Before adding a rule, list the fields it covers and confirm none of them control privilege, network exposure or workload identity.
Broad .all rules masking unrelated changes
A system-wide rule set under the .all variant in argocd-cm applies to every resource of that kind in every application. A path that looks harmless for one team can hide a meaningful change for another. Prefer a per-application rule with a name and namespace scope, and treat any .all entry as a change that needs a second reviewer.
Managed fields rules that allow silent edits
Ignoring a managed fields manager tells Argo CD to disregard changes made by that manager, which is useful for controllers that legitimately write to a resource. The same rule also lets any other actor using that manager name change the object without a diff. Confirm which manager names exist in your cluster with kubectl and record why each one is excluded.
RBAC over Application and argocd-cm
Anyone who can edit an Application or the argocd-cm ConfigMap can add or widen an ignore rule, which makes RBAC the first control to check. Limit update access on Application objects and on argocd-cm to the platform team, and confirm that project-level permissions do not let application owners change their own diff settings.
Audit and review of rule changes in Git
Ignore rules are easiest to review when they live in Git with the application or system configuration they affect. Require a pull request for every change to an ignoreDifferences block or to the resource.customizations keys, and keep the rationale in the commit message or a comment next to the rule. Ask your Git host whether branch protection can enforce that review.
Periodic review against diff history
A rule that was correct when written can become too broad after a platform upgrade or a new controller. Schedule a review that compares each rule with recent sync and diff output, removes entries that no longer match anything, and narrows paths that now cover more than intended. Record the review date and the reviewer so auditors can see the rules were tested over time.
Questions teams ask before configuring ignoreDifferences
Is ignoreDifferences a fix or a workaround?
It is a documented way to tell Argo CD that a difference is expected, so it is a configuration decision rather than a bug fix. It suits fields that other controllers, webhooks or the cluster itself change after the apply, such as defaulted values, status blocks or managed fields. It stops being a sound decision when it hides a change someone made by hand or a manifest that is wrong. Each rule should name the field, the reason it drifts and the owner who accepted it. If the root cause lies in the manifest, the manifest should change instead.
How much effort does a typical ignoreDifferences rule set take?
Effort depends on how many applications drift, how many distinct causes sit behind that drift, and how well each cause is understood. A small set of rules for one controller that mutates one field is quick to write and test. Effort rises with many resource kinds, several mutating webhooks, Helm charts that generate values on each render and multiple teams who must agree on which differences are expected. Ask any provider to break the quote into discovery of drift causes, rule authoring, testing against live applications and handover of the rule set. No figure applies to every fleet, so compare quotes against the written scope.
Can our own platform team configure ignoreDifferences without a partner?
Yes, most teams with an Argo CD operator and a Git repository can write application-level rules and system-level rules in argocd-cm. The work is mainly diagnosis: reading the diff, identifying which controller or webhook changes the field, and deciding whether the difference is expected. Teams with few applications and a clear owner for each one often manage this in-house. Teams that struggle usually lack time to trace drift across many clusters or lack someone who can judge whether a field is safe to ignore. A partner can take that analysis and hand over the rules with the reasoning documented.
How long does a review cycle take for a large Argo CD fleet?
The review cycle depends on the number of applications, clusters and teams, and on how many drift causes each one produces. Each new controller version, chart upgrade or admission policy change can create new expected differences, so reviews repeat rather than happen once. Ask for the review cadence in writing, the number of applications and clusters in scope, and who approves changes to shared system-level rules. Plan the review around your change calendar so rules are checked before a controller upgrade rather than after drift appears in production.
What access and people do we need to provide for this work?
The work needs read access to the affected Argo CD applications and the target clusters, so the team can compare live objects with Git. It also needs write access to the Git repositories that hold application manifests and to argocd-cm where system-level rules live. Each application should have a named owner who can confirm which differences are expected and who approves each rule. Without an owner, rules tend to accumulate without a reason on record. Confirm the access model, change approval steps and the test environment in advance.
How do we test an ignoreDifferences rule safely before it reaches production?
Test rules on a non-production application that shows the same drift, and confirm the diff disappears while a deliberate change to a non-ignored field still appears as OutOfSync. Use a narrow JSON pointer or jq path first, and avoid broad rules that cover whole spec or metadata blocks. Check that a manual edit to the ignored field is still visible in the review process your team uses for drift. Keep rules in Git so changes are reviewed, and record the reason beside each rule. Run the same check again after a controller upgrade.
When should we fix the manifest or the controller instead of ignoring the difference?
Fix the manifest when the difference comes from a value your Git source defines incorrectly, such as a mismatched field, a random value in a Helm template or a duplicated label. Fix the controller or admission configuration when a mutating webhook or operator writes a value that conflicts with your intent. Use ignoreDifferences when another system legitimately owns the field after apply, such as an autoscaler managing replicas or a platform adding defaults. If the field is security relevant, such as a network policy or an image reference, prefer correcting the source rather than ignoring the change.
Does ignoreDifferences affect compliance evidence for change management?
It can, because ignored fields no longer appear as drift in Argo CD, so auditors who rely on sync status as evidence will see fewer differences. Document each rule with its owner, reason, scope and approval, and keep the rule history in Git. Confirm with your auditor how they want exceptions recorded, since DeployOpen prepares systems, controls and evidence but does not issue audit reports or attestations. Independent auditors and certification bodies make the final assessment.
How DeployOpen scopes and delivers ignore rule work
The sequence below turns a set of noisy diffs into narrow, version-controlled ignore rules that are agreed in writing, tested against your change history and kept under review. Each step ends with a check you can inspect.
Review diffs in your clusters
DeployOpen starts by reading the live diffs your team sees in the Argo CD UI and CLI for the affected applications. We separate fields that Kubernetes or a controller rewrites on its own from changes that point to real drift, and we note which application, resource group and namespace each one comes from. The output is a written inventory of each noisy field with its owner, source of the change and the risk if it were ignored.
Agree scope and deliverables in writing
Before any rule is written, DeployOpen and your team agree in writing which applications, clusters and resource types are in scope, which rules will be delivered at application level and which at system level, and what evidence closes the work. Your platform owners approve the list of fields that must stay compared. Most engagements are fixed-scope, so the agreed document is the baseline for any quote and for later change requests.
Write narrow rules under version control
Rules are written in Git alongside the Application or the Argo CD configuration that uses them. Each rule names a single resource group and kind, uses the narrowest JSON pointer, jq path expression or managed fields manager that matches the noise, and includes a comment explaining the cause. System-wide rules in argocd-cm are kept to resource types where the same behavior appears everywhere. The output is a reviewed pull request for each rule set.
Test rules against your change history
Each proposed rule is checked against recent Git history and sync records to confirm it suppresses only the expected differences. We replay known real changes, such as a replica count edited by an autoscaler or a field changed by an admission webhook, and confirm they still appear as drift. The check closes when every intended change is still visible and every noisy field is quiet in the diff view.
Confirm no real drift is hidden
Before rollout, DeployOpen runs a deliberate out-of-band change in a non-production cluster for each ignored field group and confirms that Argo CD still reports the application as OutOfSync and that a sync restores the Git value where that is intended. Status field and aggregated role comparison settings are reviewed separately because they change what is compared across many resources. The output is a short verification record your team can keep with the change ticket.
Roll out and hand over
Rules are merged through your normal change process, synced to the target clusters and watched for a set period agreed in the scope. DeployOpen hands over the rule inventory, the reasoning for each rule, the verification record and a runbook that explains how to add or retire a rule. Your team owns the repository from that point and can run the same checks without DeployOpen present.
Review rules through a retainer
Clusters, controllers and Argo CD versions change, and a rule that was correct last quarter can start hiding real drift. For teams that want continuous coverage, DeployOpen offers retainers that include periodic review of the rule set against new diffs and upgrade notes. Retainer scope, frequency and fees are set in a separate written agreement, and you should confirm what they include before signing.

