Basic ArgoCD setup works fine when there are only a few applications. The pressure shows up later: dozens of services, multiple environments, shared platform dependencies, and production changes that need a clear promotion trail. These are the patterns I would put in place before the GitOps repo becomes hard to reason about.

Repository Strategy

A practical approach:

  • app source code in service repos
  • deployment manifests in environment repos
  • platform/base components in shared repo

This separation keeps deployment governance independent from application release cadence.

App of Apps Pattern

Use one root application per environment that manages child apps.

Benefits:

  • consistent environment bootstrapping
  • centralized visibility
  • easier disaster recovery recreation
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: prod-root
  namespace: argocd
spec:
  project: production
  source:
    repoURL: https://github.com/company/platform-gitops
    path: environments/prod/apps
    targetRevision: main
  destination:
    server: https://kubernetes.default.svc
    namespace: argocd
  syncPolicy:
    automated:
      prune: true
      selfHeal: true

Promotion Flow Between Environments

Use explicit promotion commits instead of direct production edits:

  1. Merge to dev
  2. Validate automated tests and smoke checks
  3. Promote same artifact digest to staging
  4. Promote approved digest to prod

Key rule: promote immutable image digests, not mutable tags.

Sync Waves and Hooks

Complex systems need ordered deployment:

  • CRDs first
  • platform dependencies second
  • application workloads last

Use sync waves:

metadata:
  annotations:
    argocd.argoproj.io/sync-wave: "10"

Use pre-sync and post-sync hooks for database migrations and smoke tests.

Drift and Policy Controls

  • enable selfHeal carefully in production
  • block manual cluster edits for managed resources
  • use policy checks for critical manifests
  • alert on repeated drift

Progressive Delivery with Argo Rollouts

For high-risk services:

  • canary with metrics-based analysis
  • automatic rollback on SLO degradation
  • staged traffic increase

This combines GitOps consistency with runtime risk control.

Multi-Tenant ArgoCD Setup

  • create ArgoCD Projects per team or domain
  • restrict source repos and destination namespaces
  • enforce RBAC and SSO groups

This avoids cross-team blast radius in shared clusters.

Anti-Patterns

  • one giant repo with no environment boundaries
  • direct production commits bypassing promotion flow
  • mutable image tags in production
  • unmanaged dependencies without sync ordering

Production Baseline

  1. App of Apps per environment
  2. digest-based promotion flow
  3. sync waves for dependencies
  4. policy + RBAC boundaries
  5. progressive delivery for critical services

The baseline is intentionally boring. That is the point: GitOps should make production change reviewable and repeatable, not turn the deployment repo into a second application nobody wants to own.