π Executive Summary
TL;DR: Unmanaged Argo CD monorepos lead to outages and complexity due to high coupling and slow CI. This article outlines three GitOps repository patternsβa structured monorepo, the App-of-Apps pattern, and a multi-repo federationβto help organizations regain control and scale their deployments effectively.
π― Key Takeaways
- Implementing a strict, logical directory structure (e.g., `apps/team/service/base` and `overlays/env`) and using `CODEOWNERS` files is the lowest effort way to immediately improve clarity and reduce accidental changes in an existing monorepo.
- The ‘Hub and Spoke’ (App-of-Apps) pattern, where a root Argo CD `Application` deploys other `Application` resources, is the recommended scalable approach for most teams, offering clear separation, fine-grained RBAC, and a single pane of glass for application management.
- The ‘Federation’ (multi-repo split) pattern provides maximum team autonomy but comes with high operational overhead and a significant risk of configuration drift and inconsistent standards without robust platform engineering practices.
Tired of your Argo CD monorepo becoming an unmanageable beast? I’m breaking down three battle-tested GitOps repository patterns, from quick fixes to a complete overhaul, to help you escape YAML hell and regain control.
It’s 2026. Your Argo CD Monorepo is a Dumpster Fire. Let’s Fix It.
I still remember the outage. It was 3 AM on a Tuesday, and a seemingly innocent config change for the prod-billing-api had just taken down our entire staging-user-auth service. The on-call dev was panicking, and I was digging through a Git history that made no sense. The culprit? Someone on another team had “helpfully” refactored a shared Kustomize base in our massive, sprawling monorepo, and the blast radius was completely invisible until everything broke. That was the night I declared war on our “everything-in-one-place” GitOps repo. This isn’t just my war story; a recent Reddit thread discussing this exact problem proves we’re all fighting the same battle against complexity.
The “Why”: The Monorepo’s Inevitable Gravity Problem
Look, we all start with a single GitOps repo for a reason: it’s simple. When you have one cluster and a handful of apps, it’s the easiest way to get started. But your company grows. The microservices multiply. Soon, you have dozens of engineers from different teams all committing to the same `/manifests` directory. The root cause isn’t malice; it’s coupling. When Team A’s staging environment config lives next to Team B’s production database config, and they both rely on a “common” base layer, you’ve created a tangled web. A single bad commit can halt deployments for everyone, CI pipelines take forever to run, and giving out Git permissions becomes an exercise in futility.
Solution 1: The “Tidy Up” – A Better Monorepo Structure
This is your first line of defense. If you can’t afford a major re-architecture right now, you can at least bring order to the chaos. This is about enforcing a strict, logical directory structure and clear ownership boundaries, even if it’s all in the same repo.
The Pattern:
Instead of a flat directory of apps, structure everything by business unit, application, and then environment. The goal is to make the blast radius obvious just by looking at the file path.
gitops-repo/
βββ apps/
βββ team-billing/
β βββ billing-api/
β β βββ base/
β β β βββ deployment.yaml
β β β βββ kustomization.yaml
β β βββ overlays/
β β βββ dev/
β β β βββ configmap.yaml
β β β βββ kustomization.yaml
β β βββ prod/
β β βββ replicas.yaml
β β βββ kustomization.yaml
β βββ reporting-svc/
β βββ base/
β βββ overlays/
βββ team-auth/
βββ auth-api/
βββ base/
βββ overlays/
Pro Tip: Immediately implement a
CODEOWNERSfile at the root of your Git repo. Map directories like/apps/team-billing/to the@TechResolve/billing-teamGitHub team. This ensures that no changes get merged into a team’s directory without their explicit approval. It’s a simple, powerful guardrail.
| Pros | Cons |
|
|
Solution 2: The “Hub and Spoke” – The App-of-Apps Pattern
This is the pattern I recommend for 90% of teams hitting scale. Itβs the canonical, battle-tested way to manage dozens or hundreds of applications without losing your mind. The core idea is that you have a root Argo CD Application that does nothing but deploy *other* Argo CD Application resources. It’s declarative GitOps all the way down.
The Pattern:
Your GitOps repo is split. One part contains the “app definitions” (the spokes), and a central part contains the “root app” (the hub) that points to them. This decouples the *intent* to deploy something from its actual manifests.
First, you have a root application that bootstraps everything:
# /bootstrap/root-app.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: root
namespace: argocd
spec:
project: default
source:
repoURL: 'https://github.com/TechResolve/gitops-repo.git'
targetRevision: HEAD
path: apps/definitions # This points to a directory of MORE Application manifests
destination:
server: 'https://kubernetes.default.svc'
namespace: argocd
syncPolicy:
automated:
prune: true
selfHeal: true
Then, in the apps/definitions directory, you define your actual applications:
# /apps/definitions/billing-api-prod.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: billing-api-prod
namespace: argocd
spec:
project: billing
source:
repoURL: 'https://github.com/TechResolve/gitops-repo.git'
targetRevision: HEAD
# This points to the ACTUAL Kubernetes manifests
path: apps/team-billing/billing-api/overlays/prod
destination:
server: 'https://kubernetes.default.svc'
namespace: billing-prod
My Take: This pattern is my default choice. It gives you a single pane of glass to see what’s running, but it allows individual teams to manage their own application definitions. We can promote a service to production by simply changing the
targetRevisionin its `Application` manifest from a feature branch to `main`. It’s clean, scalable, and Git-native.
| Pros | Cons |
|
|
Solution 3: The “Federation” – The Multi-Repo Split
This is the nuclear option. You only go here if your organization is so large and siloed that even a well-organized monorepo with the app-of-apps pattern is causing contention. Here, you abandon the monorepo entirely.
The Pattern:
Each team, or major business unit, gets its very own GitOps repository. The central platform team might maintain one for cluster-wide services (like Prometheus, cert-manager), but application teams are fully independent.
gitops-repo-platform: Managed by the SRE/Platform team. Contains cluster addons.gitops-repo-billing: Managed by the Billing team. Contains all their microservices’ Argo CD `Application` manifests.gitops-repo-auth: Managed by the Auth team.
In Argo CD, you simply add credentials for all these different repositories. Teams are responsible for their entire lifecycle. They own their manifests, their deployment pipelines, and their Argo `Application` definitions.
Warning: This path offers maximum freedom but comes with serious risks. Without a strong platform engineering practice that provides shared templates, CI jobs, and standards, you’ll get massive configuration drift. Each team will start solving the same problems in different, incompatible ways, creating a new kind of chaos. Proceed with caution.
| Pros | Cons |
|
|
My Final Advice
So, what should you do? If you’re feeling the pain today, implement Solution 1 this week. Tidy up, add a CODEOWNERS file, and stop the bleeding. While you do that, start planning your migration to Solution 2, the App-of-Apps pattern. This is the sustainable, scalable sweet spot for most organizations. Only even consider Solution 3 if you work at a massive scale where organizational boundaries are more rigid than technical ones.
There’s no single “golden pattern,” only the right pattern for your team’s scale and maturity. Now go forth and tame that repo.
– Darian Vance
π€ Frequently Asked Questions
β What is the primary problem with a sprawling Argo CD monorepo?
A sprawling Argo CD monorepo leads to high coupling, where a seemingly innocent config change can cause wide-ranging outages, slow CI pipelines, and complex Git permissions, making it unmanageable as an organization scales.
β How does the ‘Hub and Spoke’ (App-of-Apps) pattern compare to the ‘Tidy Up’ monorepo structure?
The ‘Tidy Up’ pattern is a low-effort organizational fix within a single monorepo, improving clarity and reducing accidental changes. The ‘Hub and Spoke’ pattern is a more scalable architectural change that uses nested Argo CD `Application` resources to decouple application definitions from manifests, enabling fine-grained RBAC and better organization at scale, though with a higher initial learning curve.
β What is a common implementation pitfall when adopting a multi-repo ‘Federation’ pattern, and how can it be mitigated?
A common pitfall with the ‘Federation’ pattern is configuration drift and inconsistent standards across different teams. This can be mitigated by establishing a strong platform engineering practice that provides shared templates, standardized CI jobs, and clear guidelines to ensure consistency.
Leave a Reply