Argo CD Custom Resources (CRDs) Explained: GitOps Configuration for Kubernetes

Argo CD uses Custom Resource Definitions (CRDs) to extend the Kubernetes API with declarative GitOps objects, enabling cluster-state management through Application, AppProject, and ApplicationSet resources that reconcile Git repositories with live deployments.

Argo CD implements its core functionality through Kubernetes Custom Resource Definitions (CRDs), allowing you to define GitOps workflows using native declarative syntax. These CRDs transform Argo CD into a Kubernetes controller that watches custom resources to synchronize cluster state with version-controlled manifests. Understanding the structure, lifecycle, and implementation details of these CRDs is critical for troubleshooting sync failures, managing multi-tenant environments, and extending the platform with custom operators.

Core Argo CD CRD Types

Argo CD ships with several CRDs that define its primary API objects. These definitions reside in manifests/crds/ and establish the schema for GitOps resources.

Application CRD

The applications.argoproj.io CRD represents a single deployable unit in Argo CD. Defined in manifests/crds/application-crd.yaml, this resource specifies:

  • Source: Git repository URL, path, and target revision
  • Destination: Target cluster and namespace
  • Sync Policy: Automated synchronization, pruning, and self-healing settings
  • Health Checks: Resource-specific health assessment configurations

When you create an Application resource, the Argo CD controller monitors its specification and reconciles the live cluster state with the desired state defined in Git.

AppProject CRD

The appprojects.argoproj.io CRD, defined in manifests/crds/appproject-crd.yaml, provides multi-tenancy and governance controls:

  • RBAC: Role-based access control for teams and applications
  • Source Repositories: Allowed Git repository patterns
  • Destination Clusters: Permitted target clusters and namespaces
  • Sync Windows: Time-based deployment restrictions

Projects group related Applications and enforce organizational policies before sync operations execute.

ApplicationSet CRD

The applicationset.argoproj.io CRD, located in manifests/crds/applicationset-crd.yaml, enables template-based Application generation. This resource uses generators (Git directory, List, Cluster, or SCM provider) to dynamically create multiple Application objects from a single template, streamlining management of microservices or multi-cluster deployments.

How Argo CD Watches and Reconciles CRDs

The Argo CD architecture uses the Kubernetes controller pattern to monitor CRD state changes and execute synchronization logic.

Dynamic Client and Informer Setup

The application controller establishes watches on custom resources through a dynamic client. In gitops-engine/pkg/sync/sync_context.go (around line 1290), the controller fetches CRD definitions to understand resource schemas:

crd, err := sc.extensionsclientset.ApiextensionsV1().
        CustomResourceDefinitions().
        Get(ctx, name, metav1.GetOptions{})

This dynamic client enables Argo CD to handle arbitrary CRDs without requiring compiled-in type definitions, supporting extensible GitOps workflows that include custom operators.

Sync Task Ordering for CRD Dependencies

When an Application includes CRD manifests, Argo CD must apply these definitions before instantiating resources of that custom type. The ordering logic resides in gitops-engine/pkg/sync/sync_tasks.go, where the controller constructs a dependency graph ensuring CRDs deploy before their dependent custom resources.

This sequencing prevents sync failures where custom resource instances would fail validation because their defining CRD hasn't reached the Established state.

Health Assessment and Status Conditions

Argo CD monitors CRD health through the status.conditions field defined in resource_customizations/apiextensions.k8s.io/CustomResourceDefinition/. The controller watches for:

  • Established: The CRD is recognized by the API server and ready for resource creation
  • NamesAccepted: The CRD's plural name is accepted and not in conflict

The UI component in ui/src/app/applications/components/resources.ts (around line 44) maps these conditions to visual indicators, displaying "Progressing" while CRDs establish and "Healthy" once accepted.

Practical CRD Usage Patterns

Deploying Applications Containing CRDs

When managing operators or applications that define their own CRDs, Argo CD handles the installation order automatically. Consider this Application manifest that deploys an operator with custom resources:

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: nginx-operator
spec:
  project: default
  source:
    repoURL: https://github.com/example/nginx-operator
    path: helm
    helm:
      valueFiles:
      - values.yaml
  destination:
    server: https://kubernetes.default.svc
    namespace: nginx-operator
  syncPolicy:
    automated:
      prune: true
      selfHeal: true

The Helm chart contains a templates/crd.yaml file defining the operator's CRD. According to the sync logic in controller/sync.go, Argo CD detects this CRD resource, applies it first, waits for the Established condition, then proceeds to create the Deployment and custom resource instances.

Generating CRD-backed Applications with ApplicationSet

For multi-tenant scenarios where each tenant requires a distinct CRD-based application, use an ApplicationSet:

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: multi-tenant
spec:
  generators:
    - git:
        repoURL: https://github.com/example/multi-tenant-repo
        directories:
          - path: tenant-*
  template:
    metadata:
      name: '{{path.basename}}'
    spec:
      project: default
      source:
        repoURL: https://github.com/example/multi-tenant-repo
        targetRevision: HEAD
        path: '{{path}}'
      destination:
        server: https://kubernetes.default.svc
        namespace: '{{path.basename}}'

Each generated Application may contain tenant-specific CRDs. Argo CD ensures proper ordering across all generated resources, waiting for each CRD to become established before creating dependent custom resources.

Key Source Files and Implementation Details

Understanding the codebase helps troubleshoot CRD-related issues:

Summary

  • Argo CD CRDs (applications, appprojects, applicationsets) extend Kubernetes to support declarative GitOps workflows through custom API objects.
  • Dynamic client architecture in sync_context.go allows Argo CD to watch and validate arbitrary CRDs without recompilation.
  • Sync ordering logic ensures CRDs reach Established status before dependent resources are created, preventing validation errors.
  • Health monitoring tracks CRD conditions through resource customizations, with UI visualization in resources.ts.
  • Multi-tenancy patterns leverage AppProjects for RBAC and ApplicationSets for generating CRD-backed Applications across environments.

Frequently Asked Questions

How does Argo CD handle CRDs that are part of an Application's source repository?

Argo CD detects CRD resources within the manifest collection and applies them before other resources. In gitops-engine/pkg/sync/sync_tasks.go, the controller constructs a task list that orders CRD creation first, then waits for the Established condition in status.conditions before proceeding with custom resource instances that depend on that definition.

Can Argo CD manage its own CRDs as part of an Application?

Yes, though this requires careful handling. When an Application includes CRD manifests that define resource types used by other manifests in the same Application, Argo CD's sync wave logic ensures the CRD applies first. However, updating existing CRD schemas requires using thereplace sync option or manual intervention, as Kubernetes restricts certain CRD modifications to prevent data loss.

Where does Argo CD store the health check logic for CRDs?

Health assessment for CRDs resides in resource_customizations/apiextensions.k8s.io/CustomResourceDefinition/, which contains Lua scripts that evaluate the CRD's status.conditions array. These scripts check for the Established and NamesAccepted conditions to determine if the CRD is ready for use, returning "Healthy", "Progressing", or "Degraded" states that appear in the UI component defined in ui/src/app/applications/components/resources.ts.

What happens when I delete an Application that owns a CRD?

Deletion behavior depends on metadata.ownerReferences and propagation policies. If the Application created the CRD and owns it, Argo CD respects the Kubernetes garbage collection propagation policy. By default, deleting the Application does not cascade to CRDs unless explicitly configured with ownerReferences and cascade flags, preventing accidental deletion of shared resource definitions that might be used by other Applications in the cluster.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →