# Argo CD Health Status Explained: Aggregation Logic and Custom Checks

> Understand Argo CD health status aggregation logic. Learn how it prioritizes resource health and enables custom checks with Lua scripts for better application monitoring.

- Repository: [Argo Project/argo-cd](https://github.com/argoproj/argo-cd)
- Tags: deep-dive
- Published: 2026-07-15

---

**Argo CD health status aggregates individual Kubernetes resource health using a priority-based ranking system (Healthy → Suspended → Progressing → Missing → Degraded → Unknown) and supports extensible Lua scripts for custom resource definitions.**

Argo CD continuously monitors the health of deployed applications by evaluating every managed resource in the cluster. According to the argoproj/argo-cd source code, the controller’s health determination logic combines built-in Go implementations for standard resources with configurable Lua overrides for custom CRDs, providing real-time visibility through both the web UI and CLI.

## How Argo CD Aggregates Application Health Status

The core health aggregation logic resides in the controller’s `setApplicationHealth` function, located in [`controller/health.go`](https://github.com/argoproj/argo-cd/blob/main/controller/health.go). This function evaluates each resource managed by an application and determines the overall health using a five-step process:

1. **Filters ignored resources** – Resources annotated with `argocd.argoproj.io/ignore-healthcheck: "true"` are skipped (lines 46‑49).

2. **Skips self-referential applications** – An application that manages itself does not affect its own health status (line 58).

3. **Retrieves individual health** – For existing resources, the controller invokes `health.GetResourceHealth` from [`gitops-engine/pkg/health/health.go`](https://github.com/argoproj/argo-cd/blob/main/gitops-engine/pkg/health/health.go), applying any Lua overrides.

4. **Applies priority-based aggregation** – The application inherits the most severe status from its constituent resources, following the priority order: **Healthy → Suspended → Progressing → Missing → Degraded → Unknown**.

5. **Records degradation causes** – When health is degraded, the controller tracks up to three responsible resources using the `maxHealthCausesShown` constant and formats them via the `formatHealthCauses` function.

## Built-In Health Checks for Standard Kubernetes Resources

Argo CD ships with Go-based health implementations for common Kubernetes resource types located under `gitops-engine/pkg/health/`. These built-in checks evaluate specific conditions without requiring custom configuration:

- **Deployment** ([`health_deployment.go`](https://github.com/argoproj/argo-cd/blob/main/health_deployment.go)): Verifies that `observedGeneration` matches the desired generation and that replica counts are up-to-date.

- **Service** ([`health_service.go`](https://github.com/argoproj/argo-cd/blob/main/health_service.go)): For LoadBalancer types, checks for the presence of an external IP or hostname.

- **Ingress** ([`health_ingress.go`](https://github.com/argoproj/argo-cd/blob/main/health_ingress.go)): Validates that a load-balancer ingress entry exists.

- **CronJob** ([`health_cronjob.go`](https://github.com/argoproj/argo-cd/blob/main/health_cronjob.go)): Evaluates the last schedule status to determine if the resource is Progressing or Degraded.

These implementations return a `HealthStatus` struct that the controller aggregates according to the priority rules defined in [`controller/health.go`](https://github.com/argoproj/argo-cd/blob/main/controller/health.go).

## Custom Health Checks with Lua Scripts

When managing custom resource definitions (CRDs) that lack built-in checks, Argo CD allows operators to define health logic using Lua scripts. The Lua engine implementation in [`util/lua/lua.go`](https://github.com/argoproj/argo-cd/blob/main/util/lua/lua.go) loads and executes these scripts at runtime, producing a `HealthStatus` struct with `status` and optional `message` fields.

### Defining Custom Health Scripts

Place Lua scripts in the `resource_customizations/<group>/<kind>/health.lua` path, or register them via the `argocd-cm` ConfigMap using the key `resource.customizations.health.<group>_<kind>`. For example, to enable standard Lua libraries for a specific check, use the `resource.customizations.useOpenLibs.<group>_<kind>` key.

The following example configures a custom health check for `cert-manager.io/Certificate` resources:

```yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-cm
  namespace: argocd
data:
  resource.customizations.useOpenLibs.cert-manager.io_Certificate: "true"
  resource.customizations.health.cert-manager.io_Certificate: |
    hs = {}
    if obj.status ~= nil then
      if obj.status.conditions ~= nil then
        for _, condition in ipairs(obj.status.conditions) do
          if condition.type == "Ready" and condition.status == "False" then
            hs.status = "Degraded"
            hs.message = condition.message
            return hs
          end
          if condition.type == "Ready" and condition.status == "True" then
            hs.status = "Healthy"
            hs.message = condition.message
            return hs
          end
        end
      end
    end
    hs.status = "Progressing"
    hs.message = "Waiting for certificate"
    return hs

```

### Wildcard Support for Resource Groups

You can apply health checks to entire API groups or kinds using wildcards (`*`). The implementation uses the `doublestar` glob library to match patterns such as `*.aws.crossplane.io/*`:

```yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-cm
  namespace: argocd
data:
  resource.customizations: |
    "*.aws.crossplane.io/*":
      health.lua: |
        hs = {}
        if obj.status ~= nil and obj.status.state == "available" then
          hs.status = "Healthy"
        else
          hs.status = "Degraded"
          hs.message = obj.status.state or "unknown"
        end
        return hs

```

## Monitoring Health Status in the Argo CD UI and CLI

Once calculated, health status surfaces in both the web interface and command-line tools, reflecting the aggregation logic from [`controller/health.go`](https://github.com/argoproj/argo-cd/blob/main/controller/health.go).

**Web UI**: The Applications view displays an aggregated health badge. Selecting a specific resource reveals its individual health status and a "Caused by …" summary generated by the `formatHealthCauses` function.

**CLI**: The `argocd app get` command (implemented in [`cmd/argocd/commands/app.go`](https://github.com/argoproj/argo-cd/blob/main/cmd/argocd/commands/app.go)) retrieves and displays the current health status along with problematic resources:

```bash
argocd app get my-app --refresh

```

Example output includes:

```

Health: Degraded
Caused by apps/Deployment:default/nginx-deployment

```

## Summary

- Argo CD determines **application health status** by aggregating individual resource health using the priority order: Healthy → Suspended → Progressing → Missing → Degraded → Unknown.
- The aggregation logic lives in [`controller/health.go`](https://github.com/argoproj/argo-cd/blob/main/controller/health.go), specifically the `setApplicationHealth` function, which respects ignore annotations and skips self-referential applications.
- Built-in checks for standard resources (Deployments, Services, Ingresses) reside in `gitops-engine/pkg/health/` and evaluate resource-specific conditions.
- Custom Lua scripts extend health checking to CRDs via `argocd-cm` ConfigMap entries or `resource_customizations/` paths, with wildcard support using the `doublestar` library.
- Degradation causes are tracked (up to three resources via `maxHealthCausesShown`) and displayed in both the UI and CLI.

## Frequently Asked Questions

### How does Argo CD determine the overall health of an application?

Argo CD evaluates every managed resource through the `setApplicationHealth` function in [`controller/health.go`](https://github.com/argoproj/argo-cd/blob/main/controller/health.go). It polls each resource's health status—using built-in Go logic or custom Lua scripts—and assigns the application the most severe status found, following the priority chain from Healthy (best) to Unknown (worst).

### Can I disable health checks for specific resources?

Yes. Add the annotation `argocd.argoproj.io/ignore-healthcheck: "true"` to any resource manifest. The controller will skip health evaluation for that resource during aggregation, as implemented in lines 46‑49 of [`controller/health.go`](https://github.com/argoproj/argo-cd/blob/main/controller/health.go).

### Where are custom Lua health scripts stored in the Argo CD configuration?

Custom scripts can be placed in the `resource_customizations/<group>/<kind>/health.lua` file path within your Argo CD configuration, or defined inline in the `argocd-cm` ConfigMap using keys like `resource.customizations.health.<group>_<kind>`. The Lua engine in [`util/lua/lua.go`](https://github.com/argoproj/argo-cd/blob/main/util/lua/lua.go) executes these scripts at runtime.

### What is the priority order for Argo CD health statuses?

Argo CD uses the following priority order when aggregating health status, from least severe to most severe: **Healthy**, **Suspended**, **Progressing**, **Missing**, **Degraded**, **Unknown**. The application status reflects the worst condition present among its managed resources.