---
title: "ArgoCD Patterns: App of Apps, ApplicationSets, Multi-Environment Management, and Source Strategies"
description: "Production patterns for ArgoCD including App of Apps, ApplicationSet generators, project-scoped access control, multi-environment directory structures, and choosing between Helm and Kustomize sources."
url: https://agent-zone.ai/knowledge/cicd/argocd-patterns/
section: knowledge
date: 2026-02-22
categories: ["cicd"]
tags: ["argocd","gitops","applicationsets","helm","kustomize","multi-environment"]
skills: ["gitops-architecture","argocd-patterns","multi-cluster-management"]
tools: ["argocd","helm","kustomize","kubectl"]
levels: ["intermediate"]
word_count: 864
formats:
  json: https://agent-zone.ai/knowledge/cicd/argocd-patterns/index.json
  html: https://agent-zone.ai/knowledge/cicd/argocd-patterns/?format=html
  api: https://api.agent-zone.ai/api/v1/knowledge/search?q=ArgoCD+Patterns%3A+App+of+Apps%2C+ApplicationSets%2C+Multi-Environment+Management%2C+and+Source+Strategies
---


# ArgoCD Patterns

Once ArgoCD is running and you have a few applications deployed, you hit a scaling problem: managing dozens or hundreds of Application resources by hand is unsustainable. These patterns solve that.

## App of Apps

The App of Apps pattern uses one ArgoCD Application to manage other Application resources. You create a "root" application that points to a directory containing Application YAML files. When ArgoCD syncs the root app, it creates all the child applications.

Root application:

```yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: root-app
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://github.com/myorg/gitops-config.git
    targetRevision: main
    path: argocd/apps
  destination:
    server: https://kubernetes.default.svc
    namespace: argocd
```

The `argocd/apps/` directory contains individual Application manifests:

```
argocd/apps/
  frontend.yaml
  backend-api.yaml
  postgres.yaml
  redis.yaml
  monitoring.yaml
```

Each file is a standard Application CRD. When you add a new file to this directory and push to Git, ArgoCD automatically creates the new application. When you remove a file, ArgoCD deletes the application (if prune is enabled on the root app).

This pattern is simple and transparent. The downside is repetition -- every Application YAML has boilerplate that differs only in the app name, path, or namespace.

## ApplicationSets

ApplicationSets eliminate that boilerplate. An ApplicationSet is a CRD that generates Application resources from templates and generators.

### Git Generator

Creates one Application per directory in a repo:

```yaml
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: all-apps
  namespace: argocd
spec:
  generators:
    - git:
        repoURL: https://github.com/myorg/gitops-config.git
        revision: main
        directories:
          - path: apps/*
  template:
    metadata:
      name: '{{path.basename}}'
    spec:
      project: default
      source:
        repoURL: https://github.com/myorg/gitops-config.git
        targetRevision: main
        path: '{{path}}'
      destination:
        server: https://kubernetes.default.svc
        namespace: '{{path.basename}}'
```

If the repo has `apps/frontend/`, `apps/backend/`, and `apps/redis/`, this generates three Application resources automatically. Add a new directory, get a new application. Delete a directory, the application is removed.

### Cluster Generator

Creates one Application per registered cluster. Useful for deploying the same stack across multiple clusters:

```yaml
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: monitoring-stack
  namespace: argocd
spec:
  generators:
    - clusters:
        selector:
          matchLabels:
            env: production
  template:
    metadata:
      name: 'monitoring-{{name}}'
    spec:
      project: default
      source:
        repoURL: https://github.com/myorg/gitops-config.git
        targetRevision: main
        path: monitoring
      destination:
        server: '{{server}}'
        namespace: monitoring
```

This deploys the monitoring stack to every cluster labeled `env: production`. When you register a new production cluster with ArgoCD, the monitoring stack is deployed automatically.

### Matrix Generator

Combines two generators to produce the cross-product. Deploy every app to every cluster:

```yaml
spec:
  generators:
    - matrix:
        generators:
          - git:
              repoURL: https://github.com/myorg/gitops-config.git
              revision: main
              directories:
                - path: apps/*
          - clusters:
              selector:
                matchLabels:
                  env: production
  template:
    metadata:
      name: '{{path.basename}}-{{name}}'
    spec:
      source:
        path: '{{path}}'
      destination:
        server: '{{server}}'
        namespace: '{{path.basename}}'
```

If you have 5 apps and 3 clusters, this generates 15 Application resources.

## Project-Scoped Access Control

ArgoCD projects restrict what applications can do. The `default` project allows everything. Production environments should use dedicated projects:

```yaml
apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata:
  name: team-backend
  namespace: argocd
spec:
  description: Backend team applications
  sourceRepos:
    - https://github.com/myorg/backend-manifests.git
  destinations:
    - namespace: 'backend-*'
      server: https://kubernetes.default.svc
  clusterResourceWhitelist:
    - group: ''
      kind: Namespace
  namespaceResourceBlacklist:
    - group: ''
      kind: ResourceQuota
  roles:
    - name: developer
      description: Backend developers
      policies:
        - p, proj:team-backend:developer, applications, sync, team-backend/*, allow
        - p, proj:team-backend:developer, applications, get, team-backend/*, allow
      groups:
        - backend-team
```

This project allows the backend team to deploy only from their repo, only to namespaces starting with `backend-`, and only sync and view applications -- not create or delete them. The `clusterResourceWhitelist` controls which cluster-scoped resources (like Namespaces or ClusterRoles) applications in this project can create.

## Multi-Environment Directory Structures

### Kustomize Overlays

The most common pattern for managing dev/staging/prod:

```
apps/my-app/
  base/
    deployment.yaml
    service.yaml
    kustomization.yaml
  overlays/
    dev/
      kustomization.yaml      # patches for dev
      replica-patch.yaml
    staging/
      kustomization.yaml
    production/
      kustomization.yaml
      replica-patch.yaml
      hpa.yaml
```

Each environment gets its own ArgoCD Application pointing to its overlay:

```yaml
spec:
  source:
    path: apps/my-app/overlays/production
```

### Helm Values Per Environment

Use the same chart with different values files:

```
apps/my-app/
  Chart.yaml
  values.yaml           # defaults
  values-dev.yaml
  values-staging.yaml
  values-production.yaml
```

```yaml
spec:
  source:
    path: apps/my-app
    helm:
      valueFiles:
        - values.yaml
        - values-production.yaml
```

## Helm vs Kustomize as ArgoCD Source

ArgoCD natively supports both. The choice matters for how teams interact with their deployments.

**Helm** works well when you consume third-party charts (Prometheus, PostgreSQL, nginx-ingress) and need to override values per environment. ArgoCD renders the Helm template server-side and applies the result. You never run `helm install` yourself.

**Kustomize** works well for in-house applications where the base manifests are plain YAML you control. Overlays let you patch specific fields per environment without templating syntax. ArgoCD runs `kustomize build` and applies the output.

**Plain manifests** work when you have simple applications and do not need parameterization. ArgoCD applies the YAML files directly from the specified path. This is the simplest option but does not scale when you need per-environment variation.

You can mix approaches in the same ArgoCD instance. Use Helm for third-party charts and Kustomize for your own applications. Each Application resource declares its source type independently.

## Common Mistakes

1. **Using App of Apps when ApplicationSets would eliminate all the boilerplate.** App of Apps is simpler to understand but generates maintenance overhead at scale.
2. **Not using projects to restrict applications.** The `default` project lets any Application deploy anything anywhere. This is a security and operational risk in multi-team environments.
3. **Putting environment-specific values in the base.** Base should be environment-agnostic. All environment specifics belong in overlays or environment-specific values files.
4. **Matrix generators without careful naming.** The generated Application names must be unique across the entire ArgoCD instance. Use `{{path.basename}}-{{name}}` or similar patterns to guarantee uniqueness.

