---
title: Amazon ECR Pricing: When $0.10/GB Becomes the Most Expensive Storage in Your Account
description: ECR storage is $0.10/GB-month — twice S3 Standard. Cross-region replication doubles or triples that. Enhanced scanning bills $0.09 per image scanned, on every push. Pull-through caches for Docker Hub and ECR Public add storage plus data-transfer-in. A 200-service organization with 10 environments and 3 regions can spend more on ECR than on the EKS clusters pulling from it.
url: https://www.factualminds.com/blog/amazon-ecr-pricing-storage-replication-pull-through/
datePublished: 2026-06-13T00:00:00.000Z
dateModified: 2026-06-13T00:00:00.000Z
author: palaniappan-p
category: Cost Optimization & FinOps
tags: aws-ecr, ecr-pricing, aws-pricing, cost-optimization, finops, containers
---

# Amazon ECR Pricing: When $0.10/GB Becomes the Most Expensive Storage in Your Account

> ECR storage is $0.10/GB-month — twice S3 Standard. Cross-region replication doubles or triples that. Enhanced scanning bills $0.09 per image scanned, on every push. Pull-through caches for Docker Hub and ECR Public add storage plus data-transfer-in. A 200-service organization with 10 environments and 3 regions can spend more on ECR than on the EKS clusters pulling from it.

import PricingHeroStats from '~/components/blog/PricingHeroStats.astro';
import PricingDimensionTable from '~/components/blog/PricingDimensionTable.astro';
import BillSurpriseCallout from '~/components/blog/BillSurpriseCallout.astro';
import PricingDecisionCard from '~/components/blog/PricingDecisionCard.astro';

Amazon ECR is the container registry that runs quietly in the background until you look at its line on the bill and realize it costs more than the EKS cluster pulling from it. The per-GB rate looks innocuous — $0.10/GB-month, less than a tenth of the cost of the underlying Fargate or EKS compute — yet across a real microservices estate, ECR storage compounds in ways that are uniquely invisible. There is no "your bucket has 14,000 unused objects" warning. Every CI/CD pipeline silently writes new image versions; every new region gets its own replicated catalog; every Inspector-enabled repository bills $0.09 per push.

<PricingHeroStats
  stats={[
    { value: '$0.10', label: 'Storage / GB-month', note: '2× S3 Standard; 4× S3 Standard-IA' },
    { value: '$0.09', label: 'Enhanced scan / image', note: 'Amazon Inspector integration; per push' },
    { value: '2–4×', label: 'Cross-region replication', note: 'Each destination is its own registry' },
    { value: '80–95%', label: 'Lifecycle policy saving', note: 'On unmanaged CI/CD repositories' },
  ]}
  caption="us-east-1 list prices, June 2026. Verify against the AWS ECR pricing page for your region."
/>

This post is the bill story. For deploying containers to EKS with cost-optimized autoscaling that pulls efficiently from this registry, see our [Karpenter vs Cluster Autoscaler guide](/blog/karpenter-vs-cluster-autoscaler-eks-cost-optimization/). For the broader Fargate compute math, run scenarios through our [Fargate pricing calculator](/tools/aws-fargate-pricing-calculator/).

## The Six ECR Billing Dimensions

<PricingDimensionTable
  title="ECR pricing breakdown — us-east-1, June 2026"
  intro="ECR bills across six dimensions. The storage line is the obvious one; replication and scanning are where bills go sideways."
  region="us-east-1"
  dimensions={[
    {
      name: 'Private registry storage',
      unitPrice: '$0.10 / GB-month',
      example: '500 GB of accumulated images',
      monthly: '$50.00',
      note: '2× S3 Standard; compounds without lifecycle policy',
      highlight: true,
    },
    {
      name: 'Public registry storage',
      unitPrice: '$0.10 / GB-month (50 GB free)',
      example: 'Open-source distribution',
      monthly: 'Free under 50 GB',
      note: 'For genuinely public images only',
    },
    {
      name: 'Data transfer in (push)',
      unitPrice: 'Free',
      example: 'CI/CD pushing images',
      monthly: '$0.00',
      note: 'Push is free; pull within region also free',
    },
    {
      name: 'Cross-region replication transfer',
      unitPrice: '$0.02 / GB',
      example: '100 GB replicated to 2 regions',
      monthly: '$4.00',
      note: 'Plus destination-region storage at $0.10/GB',
      highlight: true,
    },
    {
      name: 'Data transfer out to internet',
      unitPrice: 'Standard EC2 egress rates',
      example: 'CI pulling from outside AWS',
      monthly: 'Variable',
      note: 'Use pull-through cache to keep pulls in-VPC',
    },
    {
      name: 'Enhanced Scanning (Inspector)',
      unitPrice: '$0.09 per initial scan + $0.01 per re-scan',
      example: '1000 images pushed / month',
      monthly: '$90 + re-scan tail',
      note: 'Per repository opt-in; basic scan is free',
      highlight: true,
    },
    {
      name: 'Pull-through cache storage',
      unitPrice: '$0.10 / GB-month',
      example: 'Cached Docker Hub base images',
      monthly: 'Variable',
      note: 'Same rate as private storage; cuts internet egress',
    },
  ]}
  footnote="Pull from within the same region is free. Cross-region pull (rare) is billed at the standard inter-region data transfer rate."
/>

## Why a 200-Microservice Estate Generates a Five-Figure ECR Bill

The cost driver is multiplicative. Take a realistic enterprise: 200 microservices, each with ~50 image versions retained (1 per week of active development), average image size 200 MB. That is already 200 × 50 × 0.2 = 2,000 GB of image data, or $200/month in primary-region storage.

Now apply the multipliers most teams hit:

- **10 environments** (dev, qa, staging, perf, multiple feature branches with their own images, prod-canary, prod-stable, regional prod variants) → image catalog can be 3–10× the single-environment size depending on whether teams share images across environments.
- **3 regions** for production failover → cross-region replication doubles or triples the storage line, plus the data-transfer-in for each new layer push.
- **Enhanced Scanning enabled fleet-wide** → $0.09 × image push count, which at high CI/CD velocity adds thousands per month.
- **No lifecycle policy** → image catalog grows monotonically over time; what was 2,000 GB in year one becomes 20,000 GB by year three.

A 200-service estate with these multipliers can land at $5,000–$15,000/month in ECR. The same workload with disciplined lifecycle policies, replication scoped to actually-used regions, and Enhanced Scanning only on production-bound repos lands at $500–$2,000/month — a clean order-of-magnitude saving.

## The Lifecycle Policy Is Non-Negotiable

The single highest-impact ECR optimization is a registry-wide default lifecycle policy. Without it, every CI/CD push contributes to a monotonically growing image catalog. With even a modestly aggressive policy, the catalog stabilizes at a steady-state size determined by retention rules rather than developer behavior.

A reasonable starting policy:

- Retain the **last 10 tagged images** with a production tag pattern (`v*`, `release-*`, etc.).
- Retain images from the **last 30 days** regardless of tag (covers dev/staging work).
- **Expire untagged images after 7 days** (catches CI/CD intermediate builds).
- For high-velocity repos: **expire `pr-*` and `branch-*` tags after 14 days** (catches feature branch builds).

<BillSurpriseCallout
  variant="surprise"
  title="CI/CD repositories with no lifecycle policy at all"
  amount="80–95% wasted storage"
>
  Repositories created via Terraform/CDK templates that omit the lifecycle policy field accumulate every image version
  forever. Audit with `aws ecr describe-repositories | jq '.repositories[].repositoryName'` and cross-reference against
  `aws ecr get-lifecycle-policy` for each. Apply a default registry-level policy via the [ECR registry permissions and
  replication configuration](https://docs.aws.amazon.com/AmazonECR/latest/userguide/registry-settings.html) so new
  repositories inherit it automatically.
</BillSurpriseCallout>

## Cross-Region Replication: Match the Replica Set to Actual Pulls

ECR replication is straightforward to enable and dangerously easy to leave running across regions that never serve traffic. Each replication destination stores its own copy of the image catalog at $0.10/GB-month, and the initial replication of every new layer transfers cross-region at $0.02/GB.

The right approach: replicate only to regions that have running compute pulling from ECR. Audit replication configuration quarterly against the actual EKS/ECS/Lambda regional footprint. If a region has zero pulls in CloudTrail over 60 days, the replication should be disabled.

<BillSurpriseCallout
  variant="trap"
  title="Replication enabled to all regions 'just in case' of DR"
  amount="Doubles or triples storage cost"
>
  DR planning often results in replication being enabled to multiple secondary regions even when the actual DR runbook
  only fails over to one. Each unused replica region costs the same as the primary for storage. Scope replication to the
  documented DR target region; expand only when the DR plan changes.
</BillSurpriseCallout>

## Enhanced Scanning: Match to Compliance Requirements

Enhanced Scanning via Amazon Inspector is more thorough than Basic Scanning — it covers language-specific package vulnerabilities (Python packages, npm modules, Go modules, etc.) in addition to OS-level CVEs, and continuously re-scans as new CVEs are published. The trade-off is $0.09 per initial scan plus $0.01 per re-scan.

For a team pushing 1000 images/day across the fleet, the initial-scan line alone is $2,700/month, plus the re-scan tail as Inspector's CVE database updates. Across organizations with high-velocity CI/CD and Enhanced Scanning enabled by default, this routinely crosses $5,000/month.

The right approach: enable Enhanced Scanning on production-bound repositories where vulnerability tracking is a compliance or audit requirement; leave Basic Scanning (free) on development repositories. A repository naming convention (`*-prod`, `*-staging`, etc.) plus a registry-level rule can apply Enhanced selectively without per-repository decisions.

<BillSurpriseCallout
  variant="trap"
  title="Enhanced Scanning enabled fleet-wide for all repos"
  amount="$0.09 × push count; often $1,000s/mo"
>
  Most non-production CI/CD images are scanned, never deployed, and discarded by lifecycle policy days later. The scan
  cost is sunk. Enable Enhanced Scanning selectively — on repositories whose images actually reach production — and the
  spend drops by 60–80% without weakening security on the things that matter.
</BillSurpriseCallout>

## Pull-Through Caches: Bandwidth Win, Storage Cost

A pull-through cache stores ECR-side copies of images originally pulled from upstream registries (Docker Hub, ECR Public, Quay, GitHub Container Registry). The cached image bills at the standard ECR storage rate, but every subsequent pull from inside the VPC hits the local cache rather than the internet — removing internet egress data transfer and improving pull latency.

The economics:

- **Without pull-through cache**: every EKS/ECS node pulling a base image (`python:3.12`, `nginx:1.27`, etc.) does so from Docker Hub directly. Inbound to AWS is free; the pull is rate-limited by Docker Hub's anonymous-pull policy or requires an authenticated account ($5–$11/user/month for Docker Hub Pro/Team).
- **With pull-through cache**: the first pull from upstream populates the local cache. Subsequent pulls hit ECR, which is free within the same region. Storage at $0.10/GB-month adds maybe $5–$20/month for the cache of common base images; the saving is in bandwidth and reliability.

The win is most apparent at high node-launch frequency — Karpenter-driven autoscaling, frequent CI/CD spawning of test containers, ephemeral compute that pulls fresh on every launch.

## The Common Bill-Surprise Pattern: Stale Multi-Architecture Images

Multi-architecture image manifests (linux/amd64 + linux/arm64, sometimes plus windows/amd64) are increasingly common as teams adopt Graviton. Each architecture variant is stored as a separate set of layers under a single manifest. The result: a multi-arch image is roughly 2× the storage of a single-arch image.

The bill-surprise pattern: teams build multi-arch images by default even for workloads that only run on one architecture. The unused architecture's layers occupy ECR storage indefinitely.

<BillSurpriseCallout
  variant="optimization"
  title="Build multi-arch only when actually deploying to multiple architectures"
  amount="~50% storage saving on single-arch workloads"
>
  Audit your image build pipelines. If a service only ever runs on linux/amd64 (or only on linux/arm64 after a Graviton
  migration), drop the multi-arch build. Use `docker buildx build --platform linux/amd64` rather than `--platform
  linux/amd64,linux/arm64` and the resulting image is half the size in ECR.
</BillSurpriseCallout>

## When to Use ECR vs Alternatives

<PricingDecisionCard
  headline="ECR for AWS-native workloads; ECR Public only for genuinely-public artifacts; consider DIY only at extreme scale with strong cost-engineering capability."
  useWhen={[
    'Any container workload running on EKS, ECS, Fargate, App Runner, or Lambda containers — IAM-integrated pulls and in-region transfer being free are decisive',
    'Multi-region production workloads where cross-region replication latency matters — ECR replication is operationally simpler than DIY',
    'Compliance-regulated environments where private-network image distribution and Inspector integration are requirements',
    'Pull-through caches for any workload pulling Docker Hub, ECR Public, or Quay images at high frequency — converts internet pulls to in-VPC pulls',
    'ECR Public for genuinely public artifact distribution (CLI binaries, framework base images) within the 50 GB free tier',
  ]}
  avoidWhen={[
    'Long-tail image retention without lifecycle policies — accumulates the bill silently over time',
    'Enhanced Scanning enabled fleet-wide for repos that never reach production — pure waste',
    'Cross-region replication to regions with no actual compute pulling — pays for unused storage',
    'ECR Public for private use to dodge the $0.10/GB rate — exposes images to the world and violates the intended use',
    'Self-managed container registries (Harbor, Nexus, Artifactory) for AWS-native workloads — operational cost dwarfs the ECR rate at most scales',
  ]}
  footnote="ECR's premium over S3 storage is justified by integration. Most ECR cost problems are retention, replication scope, or scan scope problems — not the per-GB rate."
/>

## A 30-Day ECR Bill Cleanup Plan

**Week 1 — Apply a default lifecycle policy.** Audit repositories without a lifecycle policy via `aws ecr describe-repositories` + `aws ecr get-lifecycle-policy`. Apply a default policy (retain last 10 tagged + last 30 days + expire untagged after 7 days) across the fleet. This alone often recovers 60%+ of the storage line.

**Week 2 — Scope replication.** Map every replication rule to its destination region and cross-reference against actual compute footprint. Disable replication to regions with zero pulls in CloudTrail over 60 days. For multi-region setups, document which destinations are active vs DR-only and adjust replication frequency accordingly.

**Week 3 — Scope Enhanced Scanning.** Identify which repositories actually push to production. Disable Enhanced Scanning on repos whose images never reach production (dev sandboxes, transient CI/CD build artifacts, feature-branch builds). Keep Enhanced Scanning on production-bound repos.

**Week 4 — Audit multi-arch and pull-through cache.** Identify multi-arch images backing single-arch workloads and switch the build pipeline to single-arch. Enable pull-through caches for Docker Hub and ECR Public if the EKS/ECS fleet pulls these images at high frequency.

Cross-check the container-compute side of the picture in our [Fargate pricing calculator](/tools/aws-fargate-pricing-calculator/) to ensure the ECR cleanup pairs with right-sized compute.

## What This Post Doesn't Cover

- **Container image signing (cosign, Notation) costs** — signing operations may incur additional KMS calls; covered in the [KMS pricing post](/blog/aws-kms-pricing-keys-requests-multi-region/).
- **Cross-account ECR sharing** — uses standard IAM resource-based policies; no additional ECR-side charge.
- **Detailed comparison with third-party registries** (Harbor self-hosted, GitHub Container Registry, GitLab Container Registry) — fundamentally different operational models.
- **Air-gapped deployment patterns** — ECR has limited support for fully air-gapped use; covered in operational guides rather than pricing.

## If You Only Do One Thing This Week

Apply a default registry-level lifecycle policy that retains the last 10 tagged images plus images from the last 30 days, and expires untagged images after 7 days. This single change is non-controversial enough to ship across the fleet without per-team negotiation and typically recovers 60–80% of the ECR storage bill within a week as old layers age out. Pair with a Service Control Policy requiring lifecycle policies on new repositories and the fleet stays stable going forward.

For the broader container-compute economics — Karpenter, Spot, instance diversification — the [Karpenter vs Cluster Autoscaler post](/blog/karpenter-vs-cluster-autoscaler-eks-cost-optimization/) covers the compute side of the same architecture.

## FAQ

### Why is ECR storage twice as expensive as S3?
ECR storage costs $0.10/GB-month — exactly 2× S3 Standard at $0.023/GB-month, and 4× S3 Standard-IA. The premium reflects the additional infrastructure ECR provides: image manifest indexing, vulnerability scanning integration, registry API endpoints, IAM-controlled pulls, and authenticated cross-region replication. The premium is acceptable for the small layer-cache footprint of an active deployment fleet; it becomes a real bill when retention policies are loose and every CI/CD build leaves a 200 MB image behind for 12 months.

### How does ECR billing change with cross-region replication?
Each replication destination is its own ECR registry from a billing perspective. A 500 GB image catalog replicated from us-east-1 to us-west-2 and eu-west-1 costs $50/month in the primary region plus $50 in each replica region — $150/month total for the same image catalog. Cross-region data transfer for the initial replication (and any subsequent layer push) is billed at $0.02/GB. Replication is the right pattern when you genuinely have workloads pulling from multiple regions; it is wasteful when the destination region has no actual pulls but was enabled "in case of DR."

### Is the basic image scan really free?
Yes. ECR Basic Scanning (CVE detection against the Clair vulnerability database) is free, runs once per image push, and is enabled per-repository. Enhanced Scanning via Amazon Inspector is billed separately at $0.09 per initial image scan plus $0.01 per re-scan as new CVEs are published. For a high-velocity microservices team pushing 1000 images/day across the fleet, Enhanced Scanning lands at ~$2,700/month plus the re-scan tail. The right move for most teams: Enhanced Scanning on production-bound repositories where vulnerability tracking is a compliance requirement, Basic Scanning elsewhere.

### What does a pull-through cache actually cost?
A pull-through cache stores a local ECR copy of images originally pulled from Docker Hub, ECR Public, Quay, or GitHub Container Registry. The cached images bill at the standard ECR storage rate ($0.10/GB-month). The initial pull from the upstream registry incurs data-transfer-in (usually free) and the upstream registry may have its own rate-limit charges (Docker Hub specifically bills authenticated pulls beyond the free tier). The win is bandwidth: nodes inside the VPC pull from the local cache rather than the internet, removing internet-egress data transfer from the bill and improving pull latency dramatically.

### When do ECR lifecycle policies pay off most?
Always, but the highest-leverage application is on CI/CD build repositories where every commit produces an image. A 500-engineer organization with one image push per commit can produce 5,000–10,000 image versions per repository per year. Without a lifecycle policy, every version sits in ECR at $0.10/GB-month. A policy that retains the last 10 tagged versions plus images from the last 30 days typically reduces the repository size by 80–95% with zero impact on deployment ability. Apply at the registry-default level so all new repositories inherit the policy.

### How is the per-repository minimum charge structured?
There is no per-repository minimum. ECR bills purely on storage and operations — an empty repository costs $0. The cost driver is the layers stored across all repositories. Repository proliferation (one repo per service per branch) does not by itself cost anything; the cost is in the images sitting in those repositories. This shifts the optimization focus to image retention, not repository consolidation.

### Does ECR Public have different pricing than private ECR?
Yes. ECR Public — for distributing open-source images — bundles 50 GB of free storage and 500 GB of free outbound data transfer per month. Beyond the free tier, storage is $0.10/GB-month and data transfer follows standard regional rates. ECR Public is appropriate for genuinely public artifacts (CLI binaries, framework base images, open-source distributions). Internal images should always go in private ECR for both security (no accidental public exposure) and cost (the 50 GB free tier is not designed to subsidize private use).

---

*Source: https://www.factualminds.com/blog/amazon-ecr-pricing-storage-replication-pull-through/*
