# Diff Strategies {#diff-strategies}


Argo CD calculates the diff between the desired state and the live
state in order to define if an Application is out-of-sync. This same
logic is also used in Argo CD UI to display the differences between
live and desired states for all resources belonging to an application.

Argo CD currently has 3 different strategies to calculate diffs:

- **Legacy**: This is the main diff strategy used by default. It
  applies a 3-way diff based on live state, desired state and
  last-applied-configuration (annotation).
- **Structured-Merge Diff**: Discontinued strategy that was previously
  applied when enabling the Server-Side Apply sync option. It has been
  superseded by Server-Side Diff.
- **Server-Side Diff**: Strategy that invokes a Server-Side Apply
  in dryrun mode in order to generate the predicted live state. It is
  used automatically when the Server-Side Apply sync option is enabled.


## Structured-Merge Diff {#structured-merge-diff}




> [!WARNING]
> **Feature Discontinued**
>
> After different issues were identified by the community, this strategy has been discontinued in favour of Server-Side Diff.


This diff strategy was previously used automatically when the Server-Side
Apply sync option was enabled. Enabling Server-Side Apply now uses
[Server-Side Diff](#server-side-diff) instead. This strategy used the
[structured-merge-diff][2] library used by Kubernetes to calculate diffs
based on fields ownership. There were some challenges using this strategy
to calculate diffs for CRDs that define default values.


## Server-Side Diff {#server-side-diff}
*Current Status: Stable (Since v3.1.0)*

Server-Side Diff is used automatically for Applications that enable the
Server-Side Apply sync option, as it most accurately predicts the result
of a server-side apply. This can be overridden by explicitly setting the
`argocd.argoproj.io/compare-options: ServerSideDiff=false` annotation, in
which case the Application falls back to the Legacy (client-side) diff.

This diff strategy will execute a Server-Side Apply in dryrun mode for
each resource of the application. The response of this operation is then
compared with the live state in order to provide the diff results. The
diff results are cached and new Server-Side Apply requests to Kube API
are only triggered when:

- An Application refresh or hard-refresh is requested.
- There is a new revision in the repo which the Argo CD Application is
  targeting.
- The Argo CD Application spec changed.
- The [Resource Version][3] of the resource itself in live state changed

One advantage of Server-Side Diff is that Kubernetes Admission
Controllers will participate in the diff calculation. If for example
a validation webhook identifies a resource to be invalid, that will be
informed to Argo CD during the diff stage rather than during the sync 
stage.

Note that Server-Side Diff will not be performed during the creation of new resources.
This is to save an additional call to KubeAPI and provide a much lighter and faster diff calculation
(Non-Server-Side Apply) when resources don't exist to compare against. During resource creation performing a
Server-Side Diff won't have the benefit of the Kubernetes Admission Controller in the diff stage as validation webhooks 
won't be executed when calculating diffs if the resource is not applied in the cluster yet.


### Enabling it {#enabling-it}


Server-Side Diff can be enabled at the Argo CD Controller level or per
Application.

**Enabling Server-Side Diff for all Applications**

Add the following entry in the argocd-cmd-params-cm configmap:

```yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-cmd-params-cm
data:
  controller.diff.server.side: "true"
...
```

Note: It is necessary to restart the `argocd-application-controller`
after applying this configuration.

**Enabling Server-Side Diff for one application**

Add the following annotation in the Argo CD Application resource:

```yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  annotations:
    argocd.argoproj.io/compare-options: ServerSideDiff=true
...
```

**Disabling Server-Side Diff for one application**

If Server-Side Diff is enabled globally in your Argo CD instance, it
is possible to disable it at the application level. In order to do so,
add the following annotation in the Application resource:

```yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  annotations:
    argocd.argoproj.io/compare-options: ServerSideDiff=false
...
```

*Note: Please report any issues that forced you to disable the
Server-Side Diff feature*


### Local diff with server-side generation {#local-diff-with-server-side-generation}


`argocd app diff` supports a `--local` flag that compares a local directory against the live state. When combined with `--server-side-generate`, the CLI uploads the local source to the repo-server for manifest generation instead of running generation locally — this is useful in CI pipelines or when the local environment lacks the required tools (e.g. Helm plugins, Kustomize components).

```bash
argocd app diff my-app --local ./path --server-side-generate
```

**Controlling which files are uploaded with `--local-include`**

By default, the CLI sends files matching `*.yaml`, `*.yml`, `*.json`, `*.tpl`, and `Chart.lock`. You can override this with `--local-include`:

- Patterns **without** a path separator (e.g. `*.yaml`, `*.tpl`) match on the **filename alone**, regardless of directory depth.
- Patterns **with** a path separator (e.g. `charts/**`) match against the **relative path** and support `**` to span multiple directory levels.



> [!WARNING]
> `--local-include` **replaces** the default set entirely. Re-specify any defaults you want to keep alongside your custom patterns.




> [!NOTE]
> Kustomize apps that reference non-YAML source files in `configMapGenerator` or `secretGenerator` (e.g. `*.env`, `*.properties`) must add those patterns explicitly — no generic default covers all possible filenames and extensions.


Examples:

```bash
# Include all files under charts/ (e.g. when charts/ contains non-YAML assets)
argocd app diff my-app --local ./path --server-side-generate \
  --local-include "*.yaml" --local-include "*.yml" --local-include "*.json" \
  --local-include "*.tpl" --local-include "Chart.lock" \
  --local-include "charts/**"

# Add non-YAML Kustomize source files (e.g. configMapGenerator env files)
argocd app diff my-app --local ./path --server-side-generate \
  --local-include "*.yaml" --local-include "*.yml" --local-include "*.json" \
  --local-include "*.tpl" --local-include "Chart.lock" \
  --local-include "*.env"
```


### Mutation Webhooks {#mutation-webhooks}


Server-Side Diff does not include changes made by mutation webhooks by
default. If you want to include mutation webhooks in Argo CD diffs add
the following annotation in the Argo CD Application resource:

```yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  annotations:
    argocd.argoproj.io/compare-options: IncludeMutationWebhook=true
...
```

Note: This annotation is only effective when Server-Side Diff is
enabled. To enable both options for a given application add the
following annotation in the Argo CD Application resource:

```yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  annotations:
    argocd.argoproj.io/compare-options: ServerSideDiff=true,IncludeMutationWebhook=true
...
```

[1]: https://github.com/argoproj/argoproj/blob/main/community/feature-status.md#beta
[2]: https://github.com/kubernetes-sigs/structured-merge-diff
[3]: https://kubernetes.io/docs/reference/using-api/api-concepts/#resourceversion-in-metadata
