App-of-apps gets you to 30 services. Past that, you want ApplicationSets — Argo’s generator-based way to manage many apps from one declaration. This post is the production playbook.
The shape
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata: { name: services, namespace: argocd }
spec:
generators:
- git:
repoURL: https://github.com/example/gitops
revision: HEAD
directories:
- path: services/*
template:
metadata:
name: '{{.path.basename}}'
spec:
project: default
source:
repoURL: https://github.com/example/gitops
targetRevision: HEAD
path: '{{.path}}'
destination:
server: https://kubernetes.default.svc
namespace: '{{.path.basename}}'
syncPolicy:
automated: { prune: true, selfHeal: true }
This generates one Application per directory under services/. Add a directory; it auto-deploys.
Generators
Git directories
The above. Each subdirectory of services/ becomes one app.
Git files
generators:
- git:
repoURL: ...
files:
- path: "envs/**/config.yaml"
Each config.yaml → one app. The file’s contents become parameters.
Cluster
generators:
- clusters:
selector:
matchLabels: { env: prod }
One app per registered cluster matching the selector. Useful for fleet-wide deployments.
List
generators:
- list:
elements:
- { name: api, replicas: "3" }
- { name: worker, replicas: "10" }
Hardcoded list. Simple cases.
Matrix
generators:
- matrix:
generators:
- clusters: { selector: { matchLabels: { env: prod } } }
- git: { directories: [{ path: services/* }] }
Cartesian product. Every service × every prod cluster. Manage 5 services × 3 clusters = 15 deployments from one declaration.
Multi-cluster patterns
For a fleet of services across many clusters:
spec:
generators:
- matrix:
generators:
- clusters:
selector:
matchLabels: { env: prod }
- git:
directories: [{ path: services/* }]
template:
metadata:
name: '{{.name}}-{{.path.basename}}'
spec:
destination:
server: '{{.server}}'
namespace: '{{.path.basename}}'
source:
path: '{{.path}}/overlays/{{.metadata.labels.env}}'
Each cluster + each service combo → one Application. The path includes an overlay matching the cluster’s env label.
For GitOps with Argo CD the broader patterns.
Per-environment configs
gitops/
├── services/
│ ├── api/
│ │ ├── base/
│ │ ├── overlays/dev/
│ │ ├── overlays/staging/
│ │ └── overlays/prod/
│ └── worker/
│ └── ...
ApplicationSet renders per (service × env). Kustomize handles env differences.
Gotchas
Sync waves for ApplicationSet itself
When you change the ApplicationSet, it can recreate apps. Use preserveResourcesOnDeletion: true to avoid disasters during edits.
Resource sprawl
A bad generator produces N apps. With matrix generators, accidents balloon (service × cluster). Use applicationSetTerminalErrors to cap.
Auth across clusters
Each cluster needs Argo CD credentials. Register via argocd cluster add.
Project quotas
Bound projects to prevent ApplicationSet from spawning into namespaces you don’t intend:
apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata: { name: services }
spec:
destinations:
- server: '*'
namespace: '*'
sourceRepos: ["https://github.com/example/gitops"]
Common patterns
Onboard a new service
Create services/new-svc/. Add kustomization.yaml and overlays. ApplicationSet auto-generates. No control-plane edits.
Onboard a new cluster
Register cluster with the right labels. ApplicationSet picks it up; deploys all matching services.
Roll a config change
Edit the overlay; PR; merge. Argo CD syncs across all matching apps.
What I’d ship today
For a 2026 GitOps fleet:
- Kustomize + ApplicationSet matrix generator for service × env.
- Per-cluster registration with env labels.
- Auto-sync with prune + selfHeal for safety.
- Project quotas for blast-radius bounds.
- Per-app Slack notifications on failure.
Read this next
- GitOps with Argo CD and Flux Explained
- Platform Engineering and IDPs
- Zero-Downtime Deployments in 2026
- Kubernetes in 2026
If you want a working ApplicationSet repo with multi-cluster matrix, it’s at rajpoot.dev .
Building something AI-, backend-, or data-heavy and want a second pair of eyes? I do consulting and freelance work — see my projects and ways to reach me at rajpoot.dev .