Skip to content

2. The architecture

Argo CD is a handful of stateless processes plus a cache. There is no database, and that is a design decision worth understanding early, because it explains almost everything about how it scales and how it fails.

┌──────────────────────────────────────────────────────────┐
│ ARGO CD (a namespace in a Kubernetes cluster) │
│ │
│ ┌────────────────┐ ┌──────────────────────────┐ │
│ │ API SERVER │◄───────►│ REDIS │ │
│ │ UI, CLI, gRPC │ │ cache ONLY — no truth │ │
│ │ auth, RBAC │ │ rendered manifests, │ │
│ └───────┬────────┘ │ live resource tree │ │
│ │ └──────────▲───────────────┘ │
│ │ │ │
│ ┌───────▼────────────────────┐ │ │
│ │ APPLICATION CONTROLLER │────────┘ │
│ │ the reconciliation loop: │ │
│ │ diff, sync, health │ │
│ └───────┬──────────────┬─────┘ │
│ │ │ │
│ ┌───────▼────────┐ │ ┌────────────────────────┐│
│ │ REPO SERVER │ │ │ DEX (optional) ││
│ │ git clone, │ │ │ SSO / OIDC federation ││
│ │ helm template,│ │ └────────────────────────┘│
│ │ kustomize build│ │ │
│ └───────┬────────┘ │ │
└──────────┼──────────────┼────────────────────────────────┘
│ │
▼ ▼
┌──────────┐ ┌──────────────────────────┐
│ GIT │ │ TARGET CLUSTER(S) │
│ (+Helm │ │ (often the same cluster)│
│ repos) │ └──────────────────────────┘
└──────────┘

Five processes. Learn what each does and every troubleshooting session gets shorter, because the first question is always which one is unhappy.

This is Argo CD. Everything else is support.

It runs the reconciliation loop for every Application:

forever, for each Application:
1. ask the repo server for the DESIRED manifests
2. read the LIVE resources from the target cluster
3. compute the DIFF
4. set sync status: Synced / OutOfSync
5. assess HEALTH of every resource
6. if auto-sync is on and there is a diff: APPLY

Two things it maintains that matter operationally.

A watch on every managed cluster. Not a poll — the controller holds informers on the resource kinds it manages, so it learns about live changes immediately. This is the Kubernetes watch mechanism doing the work, and it is why drift is usually detected in seconds rather than at the next refresh.

An in-memory resource tree per cluster. Every managed resource, its owner references, and its children. This is how the UI can show you that an Application owns a Deployment which owns a ReplicaSet which owns three Pods. It is also the single largest consumer of memory in Argo CD, and chapter 13 is mostly about it.

The controller is the bottleneck and the thing you scale. It is the only component that is not trivially horizontally scalable, because each cluster is owned by exactly one controller shard. Chapter 13 covers sharding.

Its job is narrow and it is where most of the CPU goes: turn a git reference into a set of Kubernetes manifests.

input: repo URL, revision, path, and how to render
output: a list of rendered Kubernetes objects

It clones the repository, checks out the revision, works out what kind of source it is, and runs the right tool:

Detected Command run
Chart.yaml helm template
kustomization.yaml kustomize build
.jsonnet jsonnet
plain .yaml read them as-is
a plugin’s discover matches your config management plugin

Three properties worth knowing:

It is stateless and horizontally scalable. Add replicas freely; this is the easy scaling knob.

It caches aggressively in Redis, keyed by repo, revision and rendering parameters. A rendered manifest for a given commit is computed once and reused by every Application that needs it. This is why the first sync after a commit is slow and subsequent ones are instant.

It executes code from your repository. helm template runs Helm’s templating; a config management plugin runs an arbitrary binary. The repo server is therefore a genuine security boundary, and chapter 13 explains why it runs with a restricted profile and why untrusted repositories are a real risk.

Confusingly named — it is not the Kubernetes API server. It serves:

  • the web UI
  • the gRPC/REST API that argocd CLI talks to
  • authentication (local accounts, SSO via OIDC, or Dex)
  • RBAC — who may see, sync, or delete which Applications
  • webhook endpoints, so a git push can trigger an immediate refresh

It is stateless and horizontally scalable. It is also not on the critical path for reconciliation — the application controller keeps syncing perfectly well with the API server down. You lose the UI and the CLI, not the deployments. That distinction is worth knowing at 3 a.m.

The most misunderstood component. Two facts, in order of importance:

Redis holds no source of truth. It is a cache: rendered manifests, resource trees, revision metadata. Flush it entirely and Argo CD rebuilds everything from git and from the clusters.

Argo CD is nonetheless unusable without it. The controller and API server treat cache misses as expensive rather than as errors, so a Redis outage does not corrupt anything — it makes everything slow enough to look broken, with UI timeouts and reconciliation falling badly behind.

So: do not persist Redis, do not back it up, and do not ignore it either. The default single-replica deployment is a genuine single point of degradation, and the HA install ships Redis with sentinel for this reason. If you have read the Redis guide, the failover semantics there apply directly here — and losing a few cached manifests is exactly the kind of data loss that does not matter.

An optional identity broker for SSO with providers that Argo CD’s built-in OIDC support cannot handle directly — SAML, LDAP, GitHub organisations, and similar. If your provider speaks plain OIDC, configure it directly and do not run Dex at all.

There is no Argo CD database. Everything durable is a Kubernetes object in Argo CD’s namespace:

What Stored as
Applications Application CRs
Projects AppProject CRs
Repository credentials Secrets labelled argocd.argoproj.io/secret-type: repository
Cluster credentials Secrets labelled ...secret-type: cluster
Configuration ConfigMaps argocd-cm, argocd-rbac-cm, argocd-cmd-params-cm
Local users, tokens Secret argocd-secret

This has a consequence people find surprising and then come to appreciate: Argo CD’s own configuration is Kubernetes resources, so Argo CD can manage itself. An Application pointing at the repository that contains Argo CD’s own manifests is a normal and recommended setup. Chapter 11 covers the bootstrap ordering that makes it work, and chapter 14 covers the one way it goes badly wrong.

It also means backing up Argo CD is backing up those objects — or, better, keeping them in git in the first place, at which point there is nothing to back up. Which is the point.

End to end, the way it actually happens:

1. a commit lands in the manifest repository
2. either:
a webhook hits the API server → immediate refresh
or the controller's polling interval fires
(default: every 3 minutes)
3. the controller asks the repo server for manifests
at the new revision
4. the repo server clones/fetches, renders, caches
the result in Redis, returns it
5. the controller compares desired against live
→ OutOfSync
6. if auto-sync: apply the changed resources,
respecting sync waves and hooks
7. watch the resources become healthy
→ Synced + Healthy

Step 2 is the one worth configuring. The three-minute default poll is the single most common reason people say “Argo CD is slow.” It is not slow; it has not looked yet. Configure a webhook and step 2 becomes instantaneous. Chapter 13 covers this and the reasons the poll interval exists at all.

Chapter 5 traces every one of these steps in detail.

The install manifests come in two shapes and the difference is real:

Default HA
Application controller 1 replica 1 replica per shard
Repo server 1 2+
API server 1 2+
Redis 1 pod, no failover 3 + sentinel
Suitable for trying it out, small teams anything you depend on

Use the HA manifests for anything that matters. The default install is genuinely a demo configuration, and the component whose failure hurts most is the one it makes least redundant: Redis.

Note that even in HA, the application controller is one replica per shard, not several per shard. It is not active-active. Each shard’s controller is the single owner of its clusters, and it uses a Kubernetes lease for leader election if you run more. Chapter 13 explains why the design is this way and what it means for scaling.

  • Five components: application controller (the reconciliation loop), repo server (git → manifests), API server (UI, CLI, auth, RBAC, webhooks), Redis (cache), Dex (optional SSO).
  • The application controller is Argo CD. It holds watches on every managed cluster and an in-memory resource tree, which is the main memory consumer.
  • The repo server is where the CPU goes — it runs helm template and kustomize build, is stateless and easy to scale, caches in Redis, and executes code from your repositories.
  • The API server is not on the reconciliation critical path. With it down you lose the UI and CLI, not deployments.
  • Redis holds no truth but Argo CD is unusable without it. Do not persist it; do run it HA.
  • There is no database. All durable state is Kubernetes objects — Applications, AppProjects, labelled Secrets, ConfigMaps — which is why Argo CD can manage itself.
  • A change flows: commit → webhook or 3-minute poll → repo server renders → controller diffs → apply → health. The 3-minute poll is why people think Argo CD is slow; use webhooks.
  • Use the HA manifests for anything real. The controller is one replica per shard by design, not active-active.

Next: the Application resource itself — every field that matters, and the ones that quietly change behaviour.

Written by Sepuri Sai Krishna

© 2026CC BY 4.0Source