The major cloud container registries all solve the same core problem — storing and distributing container images — but differ meaningfully in how they integrate with their ecosystems, what they charge, and how they handle access control.
GitHub Container Registry (GHCR)
GHCR is tightly coupled with GitHub, which makes it a natural fit if your source code and CI/CD already live there. Public images are free and unlimited, and private images come with generous free-tier storage (500 MB for free accounts, more for paid plans). Authentication uses GitHub personal access tokens or GITHUB_TOKEN in Actions, so there's almost zero friction in CI workflows. The main limitation is that it's not deeply integrated with any specific cloud runtime — you'll need to handle image pull secrets yourself if deploying to Kubernetes or ECS. It also lacks some enterprise features like image signing and vulnerability scanning that the cloud-native registries offer built-in.
The golden path app templates provided free with essesseff use exactly this stack: GitHub (source and repos) → GitHub Actions (builds and CI) → GHCR (container images). You get a simple, integrated pipeline from code to container with minimal setup and no extra registry account.
AWS Elastic Container Registry (ECR)
ECR is the obvious choice if you're running on AWS (ECS, EKS, Fargate, Lambda containers). IAM-based authentication means no separate credential management — your task roles can pull images natively. It offers both private and public repositories (ECR Public is AWS's answer to Docker Hub). Built-in image scanning via Amazon Inspector, lifecycle policies for automatic cleanup of old images, and cross-region/cross-account replication are all strong points. Pricing is based on storage ($0.10/GB/month) and data transfer, which can add up if you're pulling across regions or out to the internet. The DX for authentication outside AWS (aws ecr get-login-password) is a bit clunky compared to a simple token.
Azure Container Registry (ACR)
ACR fits naturally into the Azure ecosystem (AKS, Azure Container Instances, App Service). It comes in three tiers — Basic, Standard, and Premium — with Premium adding geo-replication, content trust (image signing via Notary), private endpoints, and customer-managed encryption keys. ACR Tasks is a notable differentiator: you can build images directly in Azure without needing a local Docker daemon or separate CI system. Integration with Microsoft Entra ID (formerly Azure AD) makes access control straightforward in enterprise environments. Pricing is tier-based (starting around $5/month for Basic) plus storage and networking.
Google Artifact Registry (GAR)
Google's current offering (successor to GCR) supports not just container images but also language packages (Maven, npm, Python, etc.). It integrates with GKE, Cloud Run, and Cloud Build. IAM-based access, vulnerability scanning via Container Analysis, and multi-region support are all built in. Pricing is similar to ECR — storage plus network egress. If you're in the Google Cloud ecosystem, it's the straightforward choice.
Docker Hub
Still the default public registry and the place most open-source images live. Free tier allows one private repo and unlimited public repos, but pull rate limits (100 pulls/6hr for anonymous, 200 for free authenticated) pushed many teams toward alternatives. Paid plans ($5–$24/month) remove limits and add features. It remains the most universal option but lacks the deep cloud-provider integration of the others.
How to Choose
The decision usually comes down to where you deploy and where your CI runs. If you're all-in on one cloud provider, use their native registry — the IAM integration alone is worth it, and you avoid cross-cloud egress costs. If you're multi-cloud or cloud-agnostic, GHCR is compelling for its simplicity and GitHub Actions integration. Docker Hub still makes sense for open-source distribution where you want maximum discoverability.
For enterprise requirements like image signing, geo-replication, and private networking, ACR Premium and ECR are the most mature. If you also need to host non-container artifacts (Helm charts, language packages), Google's Artifact Registry and Azure's ACR have broader artifact support built in.
Extending Beyond GHCR
As we mentioned earlier, the golden path app templates provided out-of-the-box with essesseff opt for GitHub → GitHub Actions → GHCR. Those OOTB templates are a starting point for essesseff team account–specific templates: you can extend them (for example, by propagating images from GHCR to ECR) according to the needs of each Kubernetes environment. When you do, the way you configure “which registry” is straightforward.
Argo CD doesn’t pull images — the kubelet on each node does. So the question is how the image reference is set in your manifests. In the essesseff app format, each environment has its own Helm config repo (config-dev, config-qa, config-staging, config-prod), each with its own values.yaml. You set image.registry and related fields in that file per repo. So config-dev might use image.registry: ghcr.io, while config-prod uses image.registry: <account>.dkr.ecr.<region>.amazonaws.com. Each Argo CD Application points at the config repo for that environment — no runtime failover, just a clear choice per environment.
Chaining GHCR with ECR fits into this cleanly. The most common approach is CI/CD dual-push: in the same GitHub Actions workflow, build once, push to GHCR (source of truth), then log in to ECR and push the same tag. Config-prod’s values.yaml points at ECR; config-dev and other envs keep pointing at GHCR. You control exactly what lands in ECR and when. Alternatively, ECR pull-through cache lets ECR use GHCR as an upstream: you configure a pull-through rule (e.g. prefix ghcr) so that a pull to <account>.dkr.ecr.<region>.amazonaws.com/ghcr/my-org/my-app:tag causes ECR to fetch from GHCR on first pull and cache it. Then all your config repos can point at ECR; pulls are in-region and behind IAM. Good when you want in-AWS pulls without changing CI to push to ECR (you may need GHCR credentials in Secrets Manager for private images). For mirroring or decoupled sync, tools like Skopeo or Crane can copy images from GHCR to ECR on a schedule or from a separate job.
Start with the golden path (GitHub → GitHub Actions → GHCR), and when you need images in ECR or another registry, add a sync step or pull-through and set the right registry in each config repo’s values.yaml.