Skip to main content
  1. Posts/
  2. Learning ArgoCD/
  3. Platform & Infrastructure/

Repo Structure and Naming Conventions

·765 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

Repo Structure and Naming Conventions
#

What This Covers
#

Why the repo uses infra/ and apps/ as separate layers, what each folder contains, how ArgoCD connects them, and the real-world naming rationale behind these conventions.


The Two-Layer Problem
#

After adding cert-manager and Gateway API, the repo had two folders both called platform/:

PathWhat it actually contained
platform/ (root)Kubernetes manifests - ClusterIssuer, Certificate, GatewayClass
environments/<cluster>/platform/ArgoCD Application CRDs - pointers to go deploy things

Same name, completely different purpose. The rename fixes this.


The Renamed Structure
#

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
infra/                              ← shared Kubernetes manifests
  cert-manager/
    self-signed-issuer.yaml         ClusterIssuer: self-signed bootstrap
    ca-cert.yaml                    Certificate: local CA
    ca-issuer.yaml                  ClusterIssuer: signs all other certs
    kustomization.yaml
  gateway-api/
    gatewayclass.yaml               GatewayClass: traefik (cluster-scoped)
    kustomization.yaml
    crds/
      kustomization.yaml            CRD bundle reference

environments/<cluster>/
  bootstrap.yaml                    ← root App-of-Apps (applied once by hand)
  apps/                             ← ALL ArgoCD Application objects for this cluster
    cert-manager.yaml               App: installs cert-manager Helm chart
    cert-manager-config.yaml        App: deploys issuers from infra/cert-manager/
    gateway-api-crds.yaml           App: deploys CRDs from infra/gateway-api/crds/
    gateway-api-config.yaml         App: deploys GatewayClass + cluster-specific Gateway
    traefik.yaml                    App: installs Traefik Helm chart
    argocd-config.yaml              App: ArgoCD server config
    appset.yaml                     ApplicationSet: generates one App per service
  gateway-api/
    gateway.yaml                    Gateway resource (cluster-specific)
    kustomization.yaml
  argocd/
    argocd-server-config.yaml
    argocd-ingress.yaml
    argocd-admin-password.yaml
  services/
    svc1.yaml                       Helm values for svc1
    svc2.yaml
    svc3.yaml

What Each Layer Does
#

infra/ - the “what to deploy”
#

Raw Kubernetes manifests for shared infrastructure. These are cluster-agnostic - the same issuer definitions, the same GatewayClass, work on every cluster. Nothing in infra/ knows about ArgoCD; it’s plain YAML that kubectl apply could also handle.

environments/<cluster>/apps/ - the “how ArgoCD deploys it”
#

Every file here is a kind: Application or kind: ApplicationSet. These are instructions to ArgoCD, not Kubernetes resources. They say: “go to this repo path, apply it to this cluster, in this namespace, with these sync settings.”

The root bootstrap.yaml points ArgoCD at this folder. ArgoCD reads all the Application objects inside it and starts managing them - this is the App-of-Apps pattern.

environments/<cluster>/gateway-api/, argocd/, services/
#

Cluster-specific state: values, secrets, and resources that differ per cluster. Referenced by Applications in apps/, not applied directly.


The Cert-Manager Flow (with sync waves)
#

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
bootstrap.yaml
  └─ points to: environments/eu-dev-rancher/apps/
        ├─ cert-manager.yaml          wave 0  → installs cert-manager controller (Helm)
        │                                       (creates the CRDs that Issuers need)
        └─ cert-manager-config.yaml   wave 1  → applies infra/cert-manager/
                                                  self-signed-issuer.yaml
                                                  ca-cert.yaml
                                                  ca-issuer.yaml

Wave 0 must complete before wave 1 because cert-manager’s CRDs (ClusterIssuer, Certificate) don’t exist until the Helm chart installs them. Applying the issuers before the controller is ready causes ArgoCD to fail with “no matches for kind ClusterIssuer”.


The Gateway API Flow (with sync waves)
#

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
bootstrap.yaml
  └─ points to: environments/eu-dev-rancher/apps/
        ├─ gateway-api-crds.yaml      wave 1  → applies infra/gateway-api/crds/
        │                                       (installs Gateway API CRDs)
        ├─ traefik.yaml               wave 2  → installs Traefik Helm chart
        │                                       (registers GatewayClass controller)
        └─ gateway-api-config.yaml    wave 3  → two sources:
                                                  infra/gateway-api/          (GatewayClass)
                                                  environments/.../gateway-api/ (Gateway resource)

gateway-api-config.yaml uses ArgoCD’s multi-source feature. The GatewayClass lives in infra/ because it is cluster-scoped and shared. The Gateway resource lives in environments/<cluster>/gateway-api/ because it has cluster-specific settings (listeners, TLS config, hostnames).


Why infra/ and Not platform/
#

platform/ is overloaded. In this repo it was already used for two different things. In wider industry usage it also means the team/layer responsible for developer tooling, not a folder of raw manifests.

infra/ is unambiguous: it means “infrastructure manifests”. No one reads infra/cert-manager/ and thinks it contains ArgoCD Application objects.

Real-world repos that use this convention: Weaveworks Flux reference architecture, Argo CD reference app (GitHub), most multi-cluster GitOps templates from Codefresh and Grafana.


Why apps/ and Not platform/
#

Every file inside environments/<cluster>/apps/ is kind: Application or kind: ApplicationSet. Calling the folder apps/ makes this immediately obvious. It is the standard name in the Argo CD community for “the folder that holds Application manifests that ArgoCD manages”.

The previous name platform/ implied the folder contained platform infrastructure, which is the opposite of what it does - it contains the instructions to go get and deploy the platform infrastructure.


Rule of Thumb
#

If you’re writing a kind: Application or kind: ApplicationSet - it goes in environments/<cluster>/apps/. If you’re writing any other Kubernetes resource that is shared across clusters - it goes in infra/. If you’re writing a resource that is specific to one cluster - it goes in environments/<cluster>/<component>/.

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