Argo CD ApplicationSet can deploy to thousands of clusters, but it does so by not actually deploying to them directly.
Let’s see it in action. Imagine you have a simple application defined in a Git repository:
# app.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: my-app
spec:
source:
repoURL: https://github.com/my-org/my-app-config.git
targetRevision: HEAD
path: overlays/production
destination:
server: https://kubernetes.default.svc
project: default
syncPolicy:
automated:
prune: true
selfHeal: true
This Application manifest tells Argo CD how to deploy my-app to a single cluster. To deploy to many, we use an ApplicationSet.
# appset.yaml
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: multi-cluster-app
spec:
generators:
- list:
elements:
- cluster:
name: cluster-1
url: https://192.168.1.100:6443
values:
environment: dev
- cluster:
name: cluster-2
url: https://192.168.1.101:6443
values:
environment: staging
- cluster:
name: cluster-3
url: https://192.168.1.102:6443
values:
environment: prod
template:
metadata:
name: '{{.cluster.name}}-my-app'
spec:
source:
repoURL: https://github.com/my-org/my-app-config.git
targetRevision: HEAD
path: overlays/{{.values.environment}} # Dynamically set path
destination:
server: '{{.cluster.url}}' # Dynamically set cluster URL
project: default
syncPolicy:
automated:
prune: true
selfHeal: true
When you apply this ApplicationSet, Argo CD doesn’t connect to cluster-1, cluster-2, or cluster-3 itself. Instead, it creates individual Application resources for each element in the list generator. For cluster-1, it creates an Application named cluster-1-my-app pointing to https://192.168.1.100:6443 and using the path overlays/dev. For cluster-2, it creates cluster-2-my-app for https://192.168.1.101:6443 and overlays/staging, and so on.
The core problem ApplicationSet solves is managing the creation and lifecycle of thousands of identical-but-slightly-different Argo CD Application resources. Manually creating and updating these Application objects for each cluster, each environment, or each tenant would be a nightmare. ApplicationSet automates this by using generators to produce the list of target clusters/environments and a template to define the Application spec, injecting values from the generator into the template.
The generators are the heart of ApplicationSet. They provide the data that drives the creation of Application resources. The list generator is the simplest, allowing you to define a static list of elements, each containing cluster details and custom values. Other generators include cluster (which discovers clusters registered with Argo CD), git (which reads cluster/environment information from a Git repository), and matrix (which combines elements from multiple generators).
The template section is a standard Argo CD Application manifest, but with Jinja2-style templating ({{ }}) to pull in values from the generator elements. This is where you define your application’s source repository, path, and sync policies, and dynamically configure the destination cluster URL and potentially other parameters like branch, revision, or resource paths based on the generator’s output.
The real power comes from combining generators. For instance, you could use a cluster generator to find all Argo CD-registered clusters and a git generator to specify different application paths for different Git branches. ApplicationSet would then create Application resources for every combination of cluster and branch.
A common point of confusion is how Argo CD itself connects to the target clusters. Argo CD’s controller runs in a specific cluster (where Argo CD is installed). To deploy to other clusters, the Argo CD controller needs credentials. These are typically provided by registering the target clusters as Cluster secrets or by using the cluster.url field in the Application spec when the Argo CD controller has network access and valid RBAC permissions to the target cluster’s API server. The ApplicationSet merely generates these Application manifests; it doesn’t handle the actual Kubernetes API calls. The individual Application resources generated by the ApplicationSet are then processed by the Argo CD controller.
The most surprising thing is that the ApplicationSet controller doesn’t actually perform the deployments itself. It acts as a meta-controller, solely responsible for creating and updating Application resources based on its configuration. The standard Argo CD controller then picks up these generated Application resources and performs the actual synchronization to the target clusters. This separation of concerns means Argo CD can scale to manage thousands of applications across thousands of clusters because the heavy lifting of Git syncing and Kubernetes API interaction is handled by the individual Application resources managed by the core Argo CD controller, not by the ApplicationSet controller itself.
The next thing you’ll likely explore is using the git generator to dynamically provision applications based on your GitOps repository structure.