What Is Amazon ECR? The Shelf Your Images Live On
Amazon ECR (Elastic Container Registry) is a fully managed container image registry that stores, manages, and serves Docker and OCI images from within your AWS account — the shelf where your container images live before they get deployed. But here is the part almost nobody tells you: your ECR authentication token expires every 12 hours, silently breaking CI pipelines and docker pulls overnight, and there is no setting to change that lifetime. The 12-hour token is a design choice AWS made on purpose, and understanding it is the difference between an ECR setup that runs for months and one that fails every Tuesday at 3 AM.
That 12-hour authentication token is not a bug or an oversight. AWS designed it that way for security: any credential that gets compromised has a maximum blast radius of half a day. But for anyone building CI/CD pipelines — GitHub Actions, Jenkins, GitLab CI — the practical consequence is that you cannot cache a docker login credential the way you cache an SSH key or an npm token. Every pipeline run needs to re-authenticate, or you need a credential helper that does it automatically. We cover both approaches below, because this is the single most common ECR failure mode and almost nobody's first Google search finds it.
π‘Recommended AWS Foundations Reading
Master the core building blocks of AWS infrastructure, networking, and security:
- πΊ️ Regions vs. Availability Zones — The physical map that fixes half of your latency and redundancy bugs.
- π Decoding AWS ARNs — How to read the exact address syntax for any resource across accounts and regions.
- π‘️ Shared Responsibility Model — Who fixes what when an AWS service fails or leaks.
- π Public vs. Private Subnets — Visualizing traffic flow and network isolation in a VPC.
- πͺ Internet Gateway vs. NAT Gateway — Outbound internet routing without hidden cost surprises.
- π§± AWS Security Groups — Stateful firewall rules explained in plain English.
- π Service-Linked Roles — The permissions AWS automatically creates and manages for you.
- π₯️ EC2 Instance Profiles — How EC2 instances access services without hardcoded access keys.
- π¨ Root User vs. IAM User — Why you should lock away root credentials immediately.
- π AWS MFA Setup Guide — Clear the console nagging banner and secure your account in 3 minutes.
Now, the bigger picture: ECR is one of those AWS services that sounds complicated because the name is long and the descriptions use phrases like "resource-based permissions using AWS IAM." In reality, the core concept is genuinely simple. You have images. You need somewhere to put them. ECR is that somewhere — a shelf, in AWS, that only you can reach, that integrates with everything else you already use in AWS.
♂️ Jake's Reality Check
"So I've got a Docker image on my laptop, and ECR is where I put it so my EC2 instance can grab it? That's it? Why does the documentation make this sound like rocket science?"
That is genuinely it. The complication is not the concept — it's the AWS ecosystem around the concept: IAM permissions, region selection, authentication tokens, lifecycle policies. But at its core, ECR is a shelf. Jake's phone shop keeps replacement screens in labeled drawers behind the counter; ECR keeps container images in labeled repositories inside your AWS account. Same idea, different inventory.
The Shelf Metaphor: Understanding ECR Through a Kitchen
Let's build the full picture with an analogy that maps cleanly to what ECR actually does, because once you see the kitchen, the architecture stops being scary.
| AWS concept | Kitchen analogy | What it actually is |
|---|---|---|
| AWS account | Your house | The top-level container that owns everything |
| ECR registry | The kitchen | One per AWS account, per region — you do not create it, it exists automatically |
| Repository | A shelf in the kitchen | A logical collection of related images — one per app or service typically |
| Image | A jar on the shelf | The actual Docker/OCI image — the runnable thing |
| Image tag | The label on the jar | A human-readable identifier like "v1.2.3" or "latest" |
| Lifecycle policy | Spring cleaning rules | Automated rules for deleting old or unused images |
| IAM permissions | Who has a key to the kitchen | AWS Identity and Access Management controls who can push/pull |
| Image scanning | Checking the jar for mold | Automated vulnerability scanning of image contents |
With that mapping in mind, the rest of ECR makes sense. When you "push an image to ECR," you are putting a jar on a specific shelf in your kitchen. When an ECS task "pulls from ECR," it is taking a jar off the shelf and using it. When you configure "cross-region replication," you are building a second kitchen in another city that automatically stocks the same jars. The vocabulary is AWS-specific; the concepts are things you already understand.
The part the analogy captures that the architecture diagrams do not
ECR's architecture is usually described in terms of registries, repositories, and images — accurate but abstract. What the kitchen analogy adds is the ownership boundary: your kitchen is yours. Nobody outside your AWS account can see your shelves, eat your food, or even know what you have stored. ECR is private by default. This is a genuine difference from Docker Hub, where public images are the norm and visibility is opt-out rather than opt-in.
There is a public version — Amazon ECR Public — a separate service for sharing images openly, similar to Docker Hub's public registry. But the default ECR experience, and the one 95% of users need, is private storage in your own account with IAM-controlled access. When someone says "ECR" without qualification, they almost always mean the private version.
Common Use Cases: Who Actually Uses ECR
Before we get into the mechanics, it helps to know the situations where ECR earns its keep:
- Deploying microservices to ECS or EKS. Each microservice is a container image in its own ECR repository. The orchestration service pulls the right version at deploy time. This is the dominant use case — the reason most people encounter ECR in the first place.
- Sharing base images across teams. A platform team builds a hardened, compliant base image (with security patches, monitoring agents, corporate configurations) and pushes it to ECR. Application teams build their images on top of that base, ensuring consistency across the organization.
- CI/CD artifact storage. Every build produces an image, every image goes to ECR, and the deployment pipeline pulls from ECR. ECR becomes the single source of truth for what was built and when.
- Multi-region deployments. With cross-region replication, the same images are available in every region your application serves, reducing pull latency and keeping deployments consistent globally.
- Disaster recovery. Having images replicated to a second region means your recovery time objective is not limited by how fast you can rebuild container images from source.
Notice what all of these have in common: the image is a deployment artifact, not just a file. ECR is not general-purpose storage like S3 — it is specifically for container images that something (ECS, EKS, a CI/CD runner, a developer's laptop) will pull and run.
Registry vs. Repository vs. Image: The Three Levels
ECR draws a three-level hierarchy, and getting it straight in your head prevents 90% of the confusion people have when first using the service.
Level 1: The registry
Every AWS account automatically has an ECR registry in each region — you do not create it, and you cannot delete it. It is a private registry provided to each AWS account, where you create one or more repositories for your images.
The registry is identified by your AWS account ID and the region. Its URI format is always:
<aws_account_id>.dkr.ecr.<region>.amazonaws.com
For example, if your account ID is 123456789012 and you are working in us-east-1, your registry is at 123456789012.dkr.ecr.us-east-1.amazonaws.com. That address is what you authenticate against and what appears in your docker tag commands.
Level 2: The repository
A repository is a logical collection within your registry where you store your Docker images, OCI images, and other OCI-compatible artifacts — usually one per application or service. You create repositories explicitly (or automatically via repository creation templates). Each repository has a name, a URI, optional tags, and its own permissions and lifecycle policy settings. A typical setup: one repository for your frontend app, one for your backend API, one for your worker process.
Level 3: The image
The image is the actual artifact — the runnable thing. You push and pull images to and from your repositories, and use them locally on your development system or in Amazon ECS task definitions and Amazon EKS pod specifications.
Each image is identified by a tag (a human-readable label like "v2.1.0" or "latest") and/or a digest (a cryptographic hash that uniquely identifies the image content). Tags are mutable by default — you can overwrite what "latest" points to — but you can enable tag immutability per repository to prevent that.
Why three levels instead of two
- One registry per account per region means the account boundary IS the security boundary — no shared infrastructure with other AWS customers.
- Repositories give you naming and organizational structure — without them, every image would pile into one undifferentiated namespace.
- Images as a separate level lets you version: multiple versions of the same app live in one repository, distinguished by tag.
Pushing Your First Image to ECR (Step by Step)
This is the process that trips people up the first time, because it involves two tools that need to work together: the AWS CLI (for authentication) and Docker (for the actual push). Here is the complete flow.
Prerequisites
- An AWS account with permissions to use ECR
- AWS CLI installed and configured (with credentials that have ECR permissions)
- Docker installed and running
- A container image built locally (or the ability to pull one)
Step 1: Authenticate Docker to your ECR registry
To authenticate Docker to an ECR registry, run the aws ecr get-login-password command, pass the token to docker login, use the value AWS for the username, and specify the ECR registry URI you want to authenticate to. If authenticating to multiple registries, repeat the command for each one.
The command:
aws ecr get-login-password --region <region> | docker login --username AWS --password-stdin <aws_account_id>.dkr.ecr.<region>.amazonaws.com
With real values substituted:
aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin 123456789012.dkr.ecr.us-east-1.amazonaws.com
What happens under the hood: the AWS CLI generates a temporary authentication token, pipes it to docker login, which stores it in Docker's credential store. That token is valid for 12 hours — after that, you need to re-run the command.
Step 2: Create a repository (if it does not exist)
aws ecr create-repository --repository-name my-app --region us-east-1
This creates a repository called "my-app" in your registry. The repository must exist before you push the image, or you must have a repository creation template defined — a feature that lets ECR auto-create repositories with predefined settings when certain actions occur.
Step 3: Tag your local image with the ECR repository URI
docker tag <local_image_id_or_name> <aws_account_id>.dkr.ecr.<region>.amazonaws.com/my-app:tag
Example:
docker tag e9ae3c220b23 123456789012.dkr.ecr.us-east-1.amazonaws.com/my-app:v1.0
If you omit the tag, it defaults to latest.
Step 4: Push the image
docker push <aws_account_id>.dkr.ecr.<region>.amazonaws.com/my-app:v1.0
Example:
docker push 123456789012.dkr.ecr.us-east-1.amazonaws.com/my-app:v1.0
Docker uploads the image layers to ECR. You will see progress output as each layer uploads. When it finishes, the image is stored and available for pulling by anything with the right IAM permissions.
Step 5: Pull the image (to verify)
docker pull <aws_account_id>.dkr.ecr.<region>.amazonaws.com/my-app:v1.0
If the authentication is still valid and the IAM permissions allow pulls, the image downloads. If you get an authentication error, the 12-hour token has likely expired — re-run the Step 1 command.
♂️ Jake's Reality Check
"So every morning I come in and my docker pull fails with some auth error, and I have to re-run that login command? Every single morning?"
Ethan's answer: "That's the 12-hour token doing its job. The fix is not to fight it — it's to automate it. In your CI pipeline, run the aws ecr get-login-password command as the first step of every job. On your local machine, alias it or use the Amazon ECR Docker Credential Helper, which handles the refresh automatically. This is a known, designed behavior, not a bug to work around."
Lifecycle Policies: Automatic Spring Cleaning for Your Shelves
Without lifecycle policies, ECR repositories accumulate images the way a kitchen accumulates expired condiment jars — slowly at first, then catastrophically. Every build pushes a new image, every image takes up storage, and storage costs money. Lifecycle policies are the answer: rules that automatically clean up old or unused images so you do not have to. You define the rules; images that match get expired on a schedule.
What lifecycle rules can do
- Expire images by count — "keep only the 10 most recent images in this repository"
- Expire images by age — "delete any image older than 30 days"
- Expire images by tag prefix — "delete all images tagged with 'dev-' older than 7 days, but keep 'prod-' images forever"
- Expire untagged images — "remove images that no longer have any tag associated"
The rules are evaluated on a schedule, and images that match get deleted automatically. You can preview what a rule would do before enabling it — so you apply it only once the preview confirms it deletes what you expect and nothing else.
Example lifecycle policy
A common configuration — keep the last 20 images, expire anything older than 90 days:
{
"rules": [
{
"rulePriority": 1,
"description": "Keep last 20 images",
"selection": {
"tagStatus": "tagged",
"tagPrefixList": ["v"],
"countType": "imageCountMoreThan",
"countNumber": 20
},
"action": { "type": "expire" }
},
{
"rulePriority": 2,
"description": "Expire images older than 90 days",
"selection": {
"tagStatus": "any",
"countType": "sinceImagePushed",
"countNumber": 90,
"countUnit": "days"
},
"action": { "type": "expire" }
}
]
}
Rules are evaluated in priority order (lower number = higher priority), and once an image is expired by one rule, later rules do not evaluate it again.
✅ Why this is the highest-ROI ECR feature
Storage is $0.10 per GB-month. A single container image can be anywhere from 50 MB to several GB depending on what is inside. If your CI builds 20 images a day, every day, and you never clean up, that is 600 images a month. At an average of 500 MB each, that is 300 GB — $30/month in storage, growing by $30 every month, forever. A lifecycle policy that keeps the last 20 and expires anything older than 30 days cuts that to a flat, predictable cost and you never think about it again.
Image Scanning: The Mold Check for Your Jars
Container images are built from base images and software packages, and those packages have vulnerabilities — known security flaws that get discovered and cataloged in public databases like CVE (Common Vulnerabilities and Exposures). ECR's image scanning feature checks your images against these databases and reports what it finds.
Each repository can be configured to scan on push — every new image pushed to the repository gets scanned automatically, and you can retrieve the results afterward.
How to enable scan on push
When creating a repository (via CLI):
aws ecr create-repository --repository-name my-app --image-scanning-configuration scanOnPush=true
Or on an existing repository (via the AWS Console):
- Open the Amazon ECR console.
- Navigate to your repository.
- Go to the repository settings.
- Find the image scanning configuration.
- Toggle "Scan on push" to enabled.
- Save.
Once enabled, every image pushed to that repository is automatically scanned. You can view results in the console or retrieve them programmatically.
What the scan tells you
Scan results include, for each vulnerability found:
- Severity — HIGH, MEDIUM, LOW, or INFORMATIONAL
- CVE ID — the identifier in the public vulnerability database
- Affected package — which software component has the vulnerability
- Description — what the vulnerability actually is
This is scanning the image contents — the operating system packages and application dependencies inside the container — not the container runtime or the host. A clean scan means "no known vulnerabilities in the software inside this image," not "this image is safe in all respects."
What scanning does NOT do
Scanning does not stop a vulnerable image from being pushed. It reports; it does not block. If you want to prevent vulnerable images from being deployed, you need to build that logic into your CI/CD pipeline: pull the scan results, check for HIGH severity findings, and fail the deployment if any are found. The scan is the data source; the enforcement is your pipeline's job.
Cross-Region and Cross-Account Replication: Kitchens in Multiple Cities
If your application runs in multiple AWS regions — us-east-1 for US users, eu-west-1 for European users, ap-southeast-1 for Asia — you want your images available in all of them without pushing manually to each. Cross-region replication handles that automatically, copying your images to where you need them. It is configured as a registry setting, on a per-Region basis.
How it works
You configure replication rules at the registry level (not per-repository). A replication rule says: "whenever an image is pushed to any repository in Region X, copy it to Region Y." The copy happens asynchronously — typically within minutes.
Configuration requires:
- Enabling replication on the source registry.
- Specifying destination regions (or cross-account destinations).
- Optionally, filtering by repository name prefix.
Once configured, the replication is automatic and requires no ongoing management. Every push to a matching repository in the source region triggers a copy to the destination.
Cross-account replication
ECR also supports replicating images between different AWS accounts. This is useful in larger organizations where one team owns the images and another team (in a different account) runs the workloads that consume them. The replication pushes the images to the consuming account's registry, where they can be pulled with that account's IAM permissions without needing cross-account access to the source.
When replication is overkill
If all your infrastructure runs in a single region, you do not need replication. The feature adds data transfer costs and doubles your storage footprint for a benefit you cannot use. Enable it when you actually deploy to multiple regions — not "in case we might someday."
Pull Through Cache: Proxying Docker Hub Through ECR
Pull through cache is one of ECR's most underappreciated features. It solves a specific problem: you want to use public images from Docker Hub or other external registries, but you do not want every EC2 instance in your fleet pulling directly from the public internet.
A pull through cache rule lets ECR cache repositories from an upstream registry in your private ECR registry. ECR periodically reaches out to the upstream registry to ensure the cached image stays up to date.
The problem it solves
Without pull through cache, if you want to use an image like nginx:latest from Docker Hub, you have two options:
- Pull directly from Docker Hub every time — requires internet access from every consuming instance, and is subject to Docker Hub's rate limits.
- Manually pull, re-tag, and push to ECR every time the upstream image updates — tedious and error-prone.
Pull through cache gives you a third option: configure ECR to proxy Docker Hub, and instances pull from ECR instead. ECR automatically fetches and caches the upstream image, keeping it up to date.
How to set it up
Pull through cache rules are configured through the ECR console in the registry settings, or through the AWS CLI. The configuration specifies an upstream registry URL (like Docker Hub) and a repository prefix that ECR uses to namespace the cached images. Once configured, pulling an image with that prefix from your ECR registry fetches it through the cache — automatically and transparently.
This feature has become more valuable since Docker Hub introduced rate limits on anonymous pulls in recent years — with pull through cache, you pull from Docker Hub once (or periodically) and serve many instances from ECR's cache.
Security and IAM: Who Has Keys to the Kitchen
ECR security is built on AWS IAM (Identity and Access Management). Every push, pull, and management operation is authorized through IAM policies, which means you have the full power of AWS's permission system — users, roles, groups, conditions, resource-level permissions — applied to your container images. You can create IAM users, groups, and roles with specific permissions to push, pull, or manage repositories.
The key IAM actions
| IAM action | What it allows | Who typically needs it |
|---|---|---|
ecr:GetDownloadUrlForLayer |
Download image layers | Anyone pulling images |
ecr:BatchGetImage |
Get image manifests | Anyone pulling images |
ecr:PutImage |
Upload image layers | CI/CD pipelines pushing images |
ecr:InitiateLayerUpload |
Begin an image upload | CI/CD pipelines |
ecr:CreateRepository |
Create new repositories | Administrators |
ecr:DeleteRepository |
Delete repositories | Administrators |
ecr:GetAuthorizationToken |
Get the auth token for docker login | Anyone authenticating |
Repository policies (resource-based permissions)
Beyond IAM identity policies (which attach to users and roles), ECR supports repository policies — resource-based policies that attach to the repository itself and control access to the repository and its contents.
Repository policies are useful when you want to grant access to principals outside your AWS account — for example, giving a partner account permission to pull from a specific repository without giving them broader access. The policy is written in the same JSON format as IAM policies but attaches to the resource rather than the identity.
Encryption at rest
Images stored in ECR are encrypted at rest using AWS KMS. You can use the default AWS-managed encryption key or specify a customer-managed KMS key for finer-grained control over who can decrypt your images. This is configured at repository creation time and cannot be changed after the repository exists.
Interface VPC Endpoints (PrivateLink)
For maximum network isolation, ECR supports AWS PrivateLink — interface VPC endpoints that let instances in your VPC communicate with ECR without traffic traversing the public internet. This is a security hardening measure typically used in environments with strict network controls, where all AWS service traffic must stay within private address space.
Tag immutability
By default, ECR image tags are mutable — you can push a new image to the same tag, overwriting what was there. For example, pushing to my-app:latest twice replaces the first image. Tag immutability, when enabled per repository, prevents this: once a tag is pushed, it cannot be overwritten. Any attempt to push to an existing tag fails with an error.
This matters for security and auditability. If your production deployments reference images by tag, a mutable tag means what "v1.0" points to can silently change. Immutable tags guarantee that the same tag always refers to the same image content — the digest never changes. Enable tag immutability on production repositories as a best practice.
ECR with CI/CD: Making the 12-Hour Token Invisible
The 12-hour token is the single biggest friction point in ECR, and every CI/CD system has a slightly different way of dealing with it. Here are the patterns that work.
The Amazon ECR Docker Credential Helper
AWS maintains an open-source credential helper for Docker that automatically obtains and refreshes ECR authentication tokens. Once configured, docker push and docker pull to your ECR registry authenticate transparently — no manual login, no expired tokens, no 3 AM failures.
Configuration involves installing the helper binary and adding an entry to Docker's config.json that tells it to use the helper for your ECR registry URI. After that, the next docker command that needs ECR authentication triggers the helper automatically.
GitHub Actions pattern
For GitHub Actions pipelines, the standard pattern is to authenticate at the start of each job:
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v2
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: us-east-1
- name: Login to Amazon ECR
id: login-ecr
run: |
aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin 123456789012.dkr.ecr.us-east-1.amazonaws.com
Because GitHub Actions runners are ephemeral — a fresh environment for every job — the 12-hour token limitation never matters. Each job authenticates from scratch, gets a fresh token, uses it, and the runner is destroyed. This is the cleanest CI/CD pattern for ECR.
Jenkins pattern
Jenkins is trickier because Jenkins agents often persist across builds. If you cache the docker login credential on a long-lived agent, it expires after 12 hours. The fix: run the login command as a shell step at the beginning of every build, not once and saved. Alternatively, install the credential helper on the Jenkins agents, which handles the refresh automatically.
GitLab CI pattern
Similar to GitHub Actions: add a before_script step that runs the get-login-password command, and every subsequent docker command in the job uses the fresh token. GitLab's ephemeral runners make this a non-issue in practice.
Pricing: What the Shelf Costs
Amazon ECR pricing is usage-based with no upfront costs or minimum fees. You pay for the amount of data you store in your repositories, data transfer from your image pushes and pulls, and image actions you opt in to such as image signing and replication.
Storage costs
| Storage tier | Price | Use case |
|---|---|---|
| ECR Standard | $0.10 per GB-month | Default — images you actively use and deploy |
| ECR Archive | First 150 TB/month: $0.10 per GB-month; over 150 TB: $0.07 per GB-month | Long-term storage of images you rarely pull |
| ECR Archive retrieval | $0.03 per GB | Cost to retrieve an image from archive |
A real cost calculation
Let's make this concrete with a typical small-team scenario:
- Three services, each with its own ECR repository
- CI builds a new image for each service once per day
- Average image size: 500 MB (a moderate Node.js or Python app)
- No lifecycle policy configured
After one month: 90 images (3 services × 30 days) × 0.5 GB = 45 GB, at $0.10/GB-month = $4.50/month. Manageable.
After six months with no cleanup: 270 GB = $27/month. After one year: 540 GB = $54/month. And it keeps growing — linearly, forever, until you either add a lifecycle policy or manually delete old images.
With a lifecycle policy that keeps the last 10 images per repository and expires anything older: 30 images total × 0.5 GB = 15 GB = $1.50/month. Flat. Predictable. Done.
Data transfer costs
Data transfer between ECR and instances in the same region falls under standard AWS same-region transfer — effectively free for the common case of pulling images from EC2, ECS, or Fargate workloads in the same region. Cross-region pulls are billed at standard AWS data transfer rates. This is why cross-region replication can add cost even though it improves performance — you are paying for the replication transfer plus the storage in the destination region.
Opt-in action costs
Some ECR features have additional per-action costs when enabled:
- Image scanning — billed per image scan
- Replication — billed for data transfer to destination regions
- Managed signing — billed per signature generated
These are opt-in features that you only pay for if you enable them. A basic ECR setup with just storage and pulls within a region has a very simple cost model: storage at $0.10/GB-month, plus data transfer for pulls from outside the region.
⚠️ The cost that surprises people
The most common ECR bill shock comes from forgotten images. A repository with a CI pipeline pushing daily, no lifecycle policy, and images averaging 800 MB accumulates 24 GB per month of new storage. After six months, that is 144 GB — $14.40/month, just from that one repository. Multiply by a few services, and a small team can hit $100+ monthly on ECR storage alone. The fix is always the same: lifecycle policies that clean up what you no longer need.
ECR vs. Docker Hub vs. Other Registries: When to Use What
ECR is not the only container registry, and knowing when to use it versus alternatives saves both money and headaches.
| Feature | Amazon ECR | Docker Hub | GitHub Container Registry |
|---|---|---|---|
| Integration with AWS | Native (IAM, ECS, EKS, CloudTrail) | None built-in | None |
| Default visibility | Private | Public (private requires paid plan) | Public or private |
| Auth mechanism | AWS IAM (12-hour tokens) | Docker ID username/password | GitHub token |
| Image scanning | Built-in | Limited on free tier; more on paid | Via third-party tools |
| Lifecycle policies | Built-in, rule-based | Manual or API-based cleanup | Manual |
| Best for | AWS-centric deployments | Open-source, public images | GitHub-centric workflows |
The honest recommendation: if you are deploying to AWS (ECS, EKS, EC2, Fargate, Lambda container images), ECR is the natural choice because of IAM integration, native performance within AWS regions, and the ecosystem features (lifecycle, replication, pull-through cache). If you are deploying to a non-AWS platform, or your images are primarily for public consumption, a different registry may fit better.
How ECR Relates to ECS, EKS, and Fargate
This is where people get confused, because the names sound similar and the services interact closely. The mental model:
| Service | What it does | Kitchen analogy |
|---|---|---|
| Amazon ECR | Stores container images | The shelf |
| Amazon ECS | Orchestrates containers — decides what runs where | The recipe book that says what to cook when |
| Amazon EKS | Managed Kubernetes — orchestrates containers via K8s | A different recipe system, using Kubernetes conventions |
| AWS Fargate | Serverless compute engine — runs containers without managing servers | The cooking appliance (no managing the stove) |
The critical clarification: ECR is not a competitor to ECS or Fargate — they are complementary services in the same workflow. ECR stores the images. ECS or EKS decides when and where to run containers from those images. Fargate provides the underlying compute that the containers actually run on. AWS's own description calls ECR "an extension of both" ECS and EKS — which is the cleanest one-line summary of the relationship you will find anywhere.
A typical deployment flow:
- Build a container image locally or in CI.
- Push the image to ECR (the shelf).
- Define an ECS task or EKS pod that references the ECR image.
- ECS or EKS pulls the image from ECR and runs it on EC2 instances or Fargate.
ECR is the storage layer. ECS/EKS are the orchestration layers. Fargate is the compute layer. You need at least one of the orchestration layers to actually run anything from ECR — ECR by itself only stores images, it does not execute them.
Troubleshooting Common ECR Problems
Problem 1: "denied: Your authorization token has expired"
Symptom: A docker push or pull that worked yesterday suddenly fails with an authentication error.
Cause: The 12-hour authentication token has expired. This is the most common ECR error and the one that catches the most people.
Fix: Re-run the authentication command:
aws ecr get-login-password --region <region> | docker login --username AWS --password-stdin <account>.dkr.ecr.<region>.amazonaws.com
For a permanent solution in CI/CD, make this the first step of every pipeline job, or use the Amazon ECR Docker Credential Helper.
Problem 2: "denied: User is not authorized to perform: ecr:PutImage"
Symptom: Authentication succeeded but the push fails with a permissions error.
Cause: The IAM user or role has authentication (a token) but not authorization (permission to push to that specific repository).
Fix: Add the necessary IAM permissions to the user or role. At minimum, pushing requires ecr:PutImage, ecr:InitiateLayerUpload, ecr:UploadLayerPart, and ecr:CompleteLayerUpload.
Problem 3: "repository not found" during push
Symptom: The push command says the repository does not exist.
Cause: The repository was never created, or it was created in a different region.
Fix: Create the repository first: aws ecr create-repository --repository-name my-app --region <region>. Verify you are pushing to the correct region's registry URI.
Problem 4: Images disappearing unexpectedly
Symptom: Images you pushed are gone from the repository.
Cause: A lifecycle policy is deleting them based on its rules.
Fix: Check the repository's lifecycle policy and adjust the rules to match your retention needs. You can preview what a policy would do before applying it.
Problem 5: Push fails with a tag-immutability error
Symptom: A CI pipeline push fails with an error about the tag already existing.
Cause: Tag immutability is enabled on the repository, and the pipeline is trying to push to a tag that already has an image.
Fix: Either push with a new tag (use a unique tag per build — a git SHA or timestamp works well), or disable tag immutability on the repository if you intentionally want to overwrite tags. The better practice is unique tags per build with immutability on.
Problem 6: Slow image pulls from a distant region
Symptom: Deployments to regions far from us-east-1 (like ap-southeast-2) take minutes instead of seconds because every image pull crosses the Pacific.
Cause: Images are stored only in one region, and every pull from another region pays the cross-region data transfer latency and cost.
Fix: Enable cross-region replication so images are automatically copied to the regions where you deploy. Pulls then come from the local region's copy.
Frequently Asked Questions
What is Amazon ECR?
Amazon Elastic Container Registry (ECR) is a fully managed container image registry service provided by AWS. It stores Docker and OCI-compatible images in private repositories within your AWS account, with IAM-based access control, and integrates with ECS, EKS, and other AWS services for deploying containers.
Is Amazon ECR free?
No, ECR has no free tier. You pay $0.10 per GB-month for standard storage, plus data transfer costs for pulls across regions. However, data transfer within the same AWS region is effectively free, and a small setup with a few images can cost pennies per month.
How do I push a Docker image to Amazon ECR?
Authenticate with aws ecr get-login-password, create a repository with aws ecr create-repository, tag your image with the ECR registry URI, then push with docker push. The full command sequence is in the pushing section above.
How long does an ECR authentication token last?
12 hours. This is a fixed duration set by AWS and cannot be configured. After 12 hours, the token expires and you must re-authenticate with the aws ecr get-login-password command. This is the most common cause of ECR pipeline failures.
What is the difference between ECR and Docker Hub?
ECR is integrated with AWS IAM for authentication and permissions, private by default, and designed for AWS-centric deployments. Docker Hub is a standalone registry service, public by default (with private repos on paid plans), and not tied to any cloud provider. ECR has built-in lifecycle policies and image scanning; Docker Hub requires paid plans for comparable features.
Can I use ECR with Kubernetes outside of AWS?
Yes. ECR serves standard OCI images over HTTPS, so any Kubernetes cluster — on-premises, GCP, Azure — can pull from ECR as long as it has valid AWS credentials and network access to the ECR endpoint. The 12-hour token still applies.
What is a lifecycle policy in ECR?
A lifecycle policy is a set of rules that automatically cleans up old or unused images in a repository. Rules can expire images by count, by age, by tag prefix, or by tag status. You can preview what a rule would do before applying it.
Does ECR support image scanning?
Yes. ECR has built-in image scanning that identifies software vulnerabilities in your container images. Each repository can be configured to scan on push, so every new image is automatically checked. Scan results include severity, CVE IDs, and affected packages.
What is ECR pull through cache?
Pull through cache is a feature that lets ECR proxy images from external registries like Docker Hub. Instead of every instance pulling directly from the public internet, ECR caches the upstream image and serves it from within AWS. This improves reliability and reduces exposure to upstream rate limits.
How does ECR relate to ECS and Fargate?
ECR stores the images. ECS (Elastic Container Service) and EKS (Elastic Kubernetes Service) are orchestration services that decide when and where to run containers. Fargate is a compute engine that runs the containers without you managing servers. They are complementary, not competing — you typically use ECR to store images and ECS or EKS to run them.
Is ECR private or public?
ECR is private by default — images stored in ECR are only accessible to principals in your AWS account (or those you explicitly grant access to via IAM or repository policies). There is a separate service called Amazon ECR Public for hosting publicly accessible images.
How much does ECR storage cost?
Standard storage is $0.10 per GB-month. ECR Archive (for long-term storage of rarely accessed images) is $0.10 per GB-month for the first 150 TB, $0.07 per GB-month above that, with a $0.03 per GB retrieval fee when you need to pull an archived image.
Can I use ECR without ECS or EKS?
Yes. ECR serves standard Docker and OCI images, so you can pull from it with docker pull on any machine that has valid AWS credentials. It works with plain Docker, Podman, and any container runtime that supports OCI registries.
What is cross-region replication in ECR?
Cross-region replication automatically copies images pushed to one AWS region to one or more other regions. This reduces latency for pulls in distant regions and provides availability if one region has issues. It is configured at the registry level and applies to matching repositories.
How do I delete images from ECR?
You can delete images via the AWS Console (select the image, click delete), via the AWS CLI (aws ecr batch-delete-image), or automatically via lifecycle policies. Deleting a repository deletes all images within it.
What is the difference between ECR Standard and ECR Archive?
ECR Standard is for images you actively deploy and pull, at $0.10 per GB-month. ECR Archive is for long-term storage of images you rarely access — it has the same base storage rate up to 150 TB but drops to $0.07 per GB-month above that tier. The catch: retrieving an archived image costs $0.03 per GB, so Archive is only worth it for images you genuinely do not expect to pull again soon — compliance copies, old releases kept for audit, that kind of thing.
Wrapping Up: The Shelf, the Kitchen, and You
Amazon ECR is a shelf. A well-built, IAM-protected, automatically-cleanable shelf with optional mold detection and replication to other kitchens, but fundamentally: a place to put your container images so other things can find them.
The two things to take away if you take away nothing else: first, the 12-hour authentication token — automate it or it will bite you. Second, lifecycle policies — set them up the day you create your first repository, because storage costs grow silently and the cleanup you do six months late is 10x harder than the cleanup you never needed to do.
Jake set up ECR for his phone shop's inventory system, hit the 12-hour token problem on day two, added the credential helper, and has not thought about it since. Ethan's verdict: "That's the goal. The best infrastructure is the kind you stop noticing. ECR gets there once you configure the authentication and the lifecycle policy and let it do its job."
Revision note. Written September 2026, covering Amazon ECR as currently offered. The 12-hour authentication token, $0.10/GB-month storage pricing, and core feature set (lifecycle policies, image scanning, replication, pull through cache) have been stable for multiple years. If you have been fighting the 12-hour token or watching your storage bill climb from forgotten images, those are solved problems — and the fact that you looked up how to solve them puts you ahead of most teams running containers in production.