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:
manifests/crds/application-crd.yaml: Core Application resource schema defining GitOps specificationsmanifests/crds/appproject-crd.yaml: Project boundaries and RBAC constraintsmanifests/crds/applicationset-crd.yaml: Template-based Application generation schemagitops-engine/pkg/sync/sync_context.go: Dynamic CRD client initialization and API extensions interactiongitops-engine/pkg/sync/sync_tasks.go: Task ordering logic ensuring CRDs precede custom resource instancesresource_customizations/apiextensions.k8s.io/CustomResourceDefinition/: Health check Lua scripts interpreting CRD status conditionshack/gen-crd-spec/main.go: Code generation utility extracting CRD specifications from Go structs
Summary
- Argo CD CRDs (
applications,appprojects,applicationsets) extend Kubernetes to support declarative GitOps workflows through custom API objects. - Dynamic client architecture in
sync_context.goallows Argo CD to watch and validate arbitrary CRDs without recompilation. - Sync ordering logic ensures CRDs reach
Establishedstatus 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →