Skip to main content
RunBook Academy

Git, CI/CD & GitOpsLXXVI · GitOps Repository ArchitectureRepo Models

Monorepo with overlays — Kustomize and Helm values in one tree

Advanced⏱ ~24 mingit

What you'll learn

  • Describe the monorepo with overlays model and identify what an overlay is
  • Use Kustomize overlays and Helm values files to express per-environment differences
  • Recognise the audit and promotion consequences of a single Git tree for all environments
  • Compare the monorepo model to the two-repo model on authorization and blast radius

Prerequisites

Verified against Git 2.55.x teaching target; 2.40+ minimum · GitHub Actions continuous service; Aug 2026 documentation baseline · Argo CD v3.5.x teaching target; v3.0+ minimum · Flux v2.9.x · Sigstore Cosign v3.1.x · SLSA v1.2 · OCI Distribution Specification v1.1 · Git LFS v3.7.1 · Kubernetes (cross-course target) 1.36.x

Not yet marked complete on this device.

The monorepo with overlays model is the opposite extreme of the two-repo pattern. Everything lives in one Git tree: the application manifests, the per-environment differences, the shared base, the secrets references. The per-environment differences are expressed by overlays - Kustomize patches or Helm values files that override fields in a shared base. The controller reads the overlay for the environment it manages.

What an overlay is

A base is the shared manifest set that defines the application at its defaults. An overlay is a directory that imports the base and applies a set of patches on top of it. The patches are the differences: replica count, image tag, resource limits, ingress hostname, secret references. The base and the overlay are both in the same repository, and the overlay is a directory you can read.

flowchart TB
    subgraph Repo["Monorepo: env-repo"]
        B["base/ - shared manifests"]
        O1["overlays/dev/"]
        O2["overlays/staging/"]
        O3["overlays/production/"]
    end
    B --> O1
    B --> O2
    B --> O3
    O1 --> C1["dev cluster"]
    O2 --> C2["staging cluster"]
    O3 --> C3["prod cluster"]

The overlay is the unit of promotion. A change to the base propagates to all overlays; a change to a single overlay only affects that environment. Promotion is “edit the overlay’s manifest to point at a new image digest, open a PR, get it reviewed, merge.”

Kustomize: bases and overlays

Kustomize is the simplest overlay tool. The base is a directory of plain Kubernetes manifests; the overlay is a kustomization.yaml that lists the base and the patches to apply.

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
  - ../../base
patches:
  - target:
      kind: Deployment
      name: payment-api
    patch: |-
      - op: replace
        path: /spec/replicas
        value: 5
images:
  - name: payment-api
    newName: ghcr.io/example/payment-api
    digest: sha256:9a3f...e21b

The image tag is replaced by digest by the overlay. The replica count is different per overlay. The shared base is identical across all environments. A change to the base is visible in PR diff for every overlay that depends on it.

Helm: values files

Helm expresses overlays as values files. The chart is the base; the values file is the overlay. A values-production.yaml overrides replicas, image, ingress, and resources for production without touching the chart.

replicaCount: 5
image:
  repository: ghcr.io/example/payment-api
  digest: sha256:9a3f...e21b
ingress:
  host: api.example.com
resources:
  requests:
    cpu: 500m
    memory: 512Mi

The chart and the values file live in the same monorepo. The controller renders the chart with the values file for the target environment.

Audit and promotion consequences

The monorepo with overlays is the single-source-of-truth design. “Source of truth” for what? For the answer to “what is running in each environment?” A reviewer reading the overlays/production/ directory sees the exact replica count, the exact digest, the exact ingress for production. There is no other repository to read.

flux create kustomization payment-api \
  --source=env-repo \
  --path=./overlays/production \
  --prune=true \
  --interval=10m

The promotion model is overlay-by-overlay. A new release means opening PRs against each overlay’s kustomization.yaml (or values file) with the new digest, and merging per environment. The PR history records that production was promoted at commit X by reviewer Y.

Under the hood

The monorepo with overlays is what most controller vendors demonstrate in their tutorials. Flux’s flux2-kustomize-helm-example and Argo CD’s guestbook example both use this shape. It is the model that maps cleanly to a single GitOps controller watching a single repository, with the controller’s --path argument pointing at the overlay directory.

The model fails when authorization and team boundaries diverge. In a multi-tenant cluster, the team that owns the application manifests is rarely the team that owns the cluster’s ingress and TLS. In a monorepo, both teams have access to the same tree, and the only way to separate their authority is a CODEOWNERS file that names different reviewers for different paths. CODEOWNERS is a workable tool but it is not a trust boundary; a CODEOWNERS violation is a code-review failure, not a security control.

Production discipline

The production rules for the monorepo with overlays model are:

  1. The base is treated as a separately versioned contract. A change to the base is a breaking change to every overlay that depends on it. The PR review for a base change names every overlay that will be affected.
  2. Each overlay has a single owning team. The CODEOWNERS file in overlays/${ENV}/ names the team that owns that environment. Pull requests against an overlay require that team’s approval.
  3. Promotion is overlay-by-overlay, not branch-by-branch. A new release opens a PR against overlays/dev/ first, then overlays/staging/, then overlays/production/. The promotion is the sequence of merged PRs, and the Git history records the order.

Cross-course references

  • Git, CI/CD & GitOps for Infrastructure Engineers - Part LXXVI-01 introduced the two-repo split; this lesson is the model that pushes the application repo’s manifests into the environment repo and uses overlays to express the differences.
  • Kubernetes for Production Sysadmins - Part XIII (Helm) covers Helm values files in depth; Part XIV (Kustomize) covers the Kustomize overlay semantics.
  • Ansible for Production Sysadmins - Part XXXVII (RepoArch) covers the analogous group_vars / host_vars split, which is the Ansible version of “base + overlay”.

Quiz

Knowledge check · 4 questions

  1. Q1. What is the promotion unit in a monorepo with overlays model?

  2. Q2. Kustomize overlays and Helm values files are functionally equivalent ways to express per-environment differences.

  3. Q3. In a monorepo with overlays, what is the trade-off of putting every environment on the same shared base, and what code-review rule compensates for it?

  4. Q4. Diagnose which file the change should target and what the review chain should look like.

    A platform engineer wants to update the ingress TLS configuration for production only. The repo is a monorepo with `base/`, `overlays/dev/`, `overlays/staging/`, `overlays/production/`. The application team owns `base/`. The platform team owns the clusters and the ingress controllers.

Passing score: 75%. Answers are checked in this browser.