Skip to main content
  1. Posts/
  2. Learning ArgoCD/
  3. Core Patterns/

App-of-Apps vs ApplicationSet - When to Use Which

·695 words·4 mins
Ravi Singh
Author
Ravi Singh
Software engineer with 15+ years building backend systems and cloud platforms across fintech, automotive, and academia. I write about the things I build, debug, and learn — so I don’t forget them.
Learning ArgoCD - This article is part of a series.
Part 4: This Article

App-of-Apps vs ApplicationSet - When to Use Which
#

The Core Difference
#

Both patterns answer the same question: how do I manage many ArgoCD Applications without manually applying each one? But they solve it at different levels.

App-of-Apps - a manually maintained parent Application that watches a directory of hand-written child Application manifests. You own every YAML.

ApplicationSet - a controller that generates Application manifests from a template + a data source (a git directory, a list of files, a cluster list, etc.). You define one template; ArgoCD stamps out N Applications.


Side-by-Side Comparison
#

App-of-AppsApplicationSet
Application manifestsHand-written per serviceAuto-generated from template
Adding a new serviceCommit a new Application YAMLCreate a new folder or values file
Per-service customisationEasy - just edit the YAMLVia generator parameters or values files
Platform controls sync policyNo - each service owns its YAMLYes - template is fixed by platform team
Services are homogeneous (same chart)Works but verboseBetter fit
Services are heterogeneous (mixed charts)Natural fitAwkward
Multi-cluster deploymentsManual - one YAML per clusterBuilt-in via Cluster generator
Bootstrap costkubectl apply once per stagekubectl apply once per ApplicationSet

The Access Control Question
#

A common constraint in real teams: dev teams cannot kubectl apply into the argocd namespace. This rules out both manually applying Application YAMLs and posting through the ArgoCD UI one app at a time.

The clean answer is ApplicationSet + Git as the interface.

1
2
3
4
5
6
7
8
9
Platform team does (one time):
  → deploys an ApplicationSet into the argocd namespace

Dev team does (ongoing):
  → creates a new folder or values file in their area of the git repo
  → opens a PR, gets it merged

ArgoCD does automatically:
  → detects the new file, generates an Application, deploys it

Dev teams never touch kubectl or the ArgoCD UI for onboarding. Git is the only interface.


Typical Enterprise Layout
#

1
2
3
4
5
6
7
8
Platform team owns:
  argocd/appsets/team-a.yaml    ← ApplicationSet (deployed once by platform)

Dev team owns:
  environments/eu-dev/team-a/   ← just create folders/files here
    values/
      svc1.yaml                 ← drop a file → Application appears automatically
      svc2.yaml

The ApplicationSet watches environments/eu-dev/team-a/values/*.yaml. When a dev team adds svc3.yaml via PR, the Application for svc3 appears without any platform team involvement.


Where ArgoCD Projects Fit In
#

Even without kubectl access, dev teams can still use the ArgoCD UI to operate their apps - check sync status, view logs, trigger a manual sync. ArgoCD Projects control what they can see and do:

  • Team A can sync apps only in team-a-project
  • They cannot modify or delete apps owned by other teams
  • They cannot change the ApplicationSet template

The UI becomes a read/operate interface. Git is the configure interface. ApplicationSet + Projects together make self-service safe.


Decision Guide
#

Use App-of-Apps when:

  • You have a small, fixed set of apps that are different enough to need individual specs
  • Services use mixed Helm charts, Kustomize, or plain manifests
  • Dev teams need to control sync policy per app (e.g. manual sync for some, automated for others)
  • Bootstrapping top-level platform components (cert-manager, ingress, ArgoCD itself)

Use ApplicationSet when:

  • Many services share the same chart and differ only in configuration
  • You want new services to appear automatically - just add a file to git
  • Deploying the same service to multiple clusters
  • A platform team manages the deployment contract; dev teams self-serve via Git

They are not mutually exclusive. A common pattern:

1
2
3
4
5
App-of-Apps (bootstrap layer)
  → cert-manager Application
  → ingress-nginx Application
  → ApplicationSet for team-a (manages all team-a services)
  → ApplicationSet for team-b (manages all team-b services)

The App-of-Apps bootstraps the few heterogeneous platform components. Each ApplicationSet handles a fleet of homogeneous services within a team boundary.


Key Takeaway
#

When dev teams have no kubectl access to the argocd namespace, the UI is not the answer - manual onboarding through the UI doesn’t scale. The right design is ApplicationSet (for self-service via Git) + ArgoCD Projects (for isolation and RBAC). Git PRs become the onboarding gate; the platform team only needs to act once per team/environment, not once per service.

Learning ArgoCD - This article is part of a series.
Part 4: This Article