Skip to main content

How to Use Amazon ECR: Managing Container Images with AWS CLI

Tags:

When building and operating containerized applications, you need a place to store your Docker images. If you're using AWS, one great answer is Amazon ECR (Elastic Container Registry) — a fully managed container image registry that integrates seamlessly with AWS services like ECS and EKS. In this article, we'll walk through how ECR works and how to create a repository, push, and pull images using the AWS CLI.

What is Amazon ECR?​

Amazon ECR is a container image registry service for storing and managing Docker images and OCI (Open Container Initiative)-compliant artifacts. Unlike public registries such as Docker Hub, ECR provides private repositories by default. Access is controlled through AWS IAM, giving you fine-grained permission management.

Images stored in ECR can be referenced directly by AWS compute services including Amazon ECS, EKS, AWS Batch, and App Runner. Since there are no data transfer charges within the same region, ECR is the natural choice when running containers on AWS.

Core ECR Concepts​

Let's clarify a few terms before you get started.

TermDescription
RegistryThe top-level container for images. One registry is created per AWS account.
RepositoryA grouping unit for images. You give it a name like myapp/frontend.
Image tagA label that identifies a specific image within a repository (e.g., latest, v1.0.0).
Image digestA hash of the image. More unique than a tag and serves as an immutable identifier.

ECR uses the following URI format. You specify this URI when referencing an image during deployment.

{account-id}.dkr.ecr.{region}.amazonaws.com/{repository-name}:{tag}

Public vs. Private Registries​

ECR offers two types of registries: private and public. Choose based on your use case.

Private RegistryPublic Registry
AccessRequires IAM authenticationAnyone can pull without authentication
Hostname{account-id}.dkr.ecr.{region}.amazonaws.compublic.ecr.aws
Primary useInternal / project image managementDistributing OSS or public images
PricingCharged by storage and data transferFree up to a certain limit

Use private registries for internal application images and public registries for distributing open-source tools or base images. This article focuses on private registries.

Security Features​

ECR includes several features to strengthen image security. Make sure to review these settings for production environments.

FeatureDescription
Image scanningDetects OS package vulnerabilities on push or on demand
Image encryptionEncrypts images in the repository using AWS KMS
Tag immutabilityPrevents overwriting a tag with a new push, ensuring image integrity
VPC endpointAccess ECR from within a VPC without going through the internet

Repository Policies​

You can attach a JSON repository policy to a repository to control which AWS accounts or services can pull or push images. By default, only IAM principals within the same account have access, but you can, for example, allow read-only access from another AWS account.

{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowCrossAccountPull",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::210987654321:root"
},
"Action": [
"ecr:GetDownloadUrlForLayer",
"ecr:BatchGetImage",
"ecr:BatchCheckLayerAvailability"
]
}
]
}

Pull Through Cache​

Pulling images from external registries like Docker Hub or Quay.io repeatedly can run into rate limits or get affected by an outage on the external registry's end. A pull-through cache caches an external registry's image in ECR the first time it's accessed, so later pulls go through ECR instead.

This reduces your dependency on external registries while keeping the benefits of ECR — IAM-based permission management and access over a private network.

Using ECR with the AWS CLI​

Let's walk through everything from creating a repository to pushing and pulling images using the AWS CLI.

Create a Repository​

Use the create-repository command to create a repository. Here's what the options do:

  • --image-scanning-configuration scanOnPush=true: Automatically runs an image scan on every push
  • --image-tag-mutability IMMUTABLE: Prevents overwriting images with the same tag
❯ aws ecr create-repository \
--repository-name myapp/frontend \
--image-scanning-configuration scanOnPush=true \
--image-tag-mutability IMMUTABLE
{
"repository": {
"repositoryArn": "arn:aws:ecr:us-east-1:123456789012:repository/myapp/frontend",
"registryId": "123456789012",
"repositoryName": "myapp/frontend",
"repositoryUri": "123456789012.dkr.ecr.us-east-1.amazonaws.com/myapp/frontend",
"createdAt": "2026-05-14T18:17:26.708000+09:00",
"imageTagMutability": "IMMUTABLE",
"imageScanningConfiguration": {
"scanOnPush": true
},
"encryptionConfiguration": {
"encryptionType": "AES256"
}
}
}

You'll use the repositoryUri shown here for push and pull operations.

Set a Repository Policy​

Set a policy on the repository you just created to allow read-only access from another AWS account (e.g., 210987654321).

❯ cat << 'EOF' > repo-policy.json
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowCrossAccountPull",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::210987654321:root"
},
"Action": [
"ecr:GetDownloadUrlForLayer",
"ecr:BatchGetImage",
"ecr:BatchCheckLayerAvailability"
]
}
]
}
EOF
❯ aws ecr set-repository-policy \
--repository-name myapp/frontend \
--policy-text file://repo-policy.json

You can check the policy you set with get-repository-policy.

❯ aws ecr get-repository-policy \
--repository-name myapp/frontend
{
"registryId": "123456789012",
"repositoryName": "myapp/frontend",
"policyText": "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Sid\":\"AllowCrossAccountPull\",\"Effect\":\"Allow\",\"Principal\":{\"AWS\":\"arn:aws:iam::210987654321:root\"},\"Action\":[\"ecr:GetDownloadUrlForLayer\",\"ecr:BatchGetImage\",\"ecr:BatchCheckLayerAvailability\"]}]}"
}

Authenticate with ECR​

To connect the Docker client to ECR, you need to obtain an authentication token and log in. Use the get-login-password command to retrieve the token and pass it to docker login.

❯ aws ecr get-login-password | \
docker login --username AWS --password-stdin \
123456789012.dkr.ecr.us-east-1.amazonaws.com
Login Succeeded

Once you see Login Succeeded, you're authenticated. The token expires after 12 hours, so re-authenticate each time you run this in a CI/CD pipeline or similar recurring workflow.

Pull an Image and Tag It​

Let's pull nginx:alpine from Docker Hub for testing purposes.

❯ docker pull nginx:alpine

Tag the pulled image with your ECR URI. The original image remains unchanged — you're just adding an alias that points to the same layers.

❯ docker tag nginx:alpine \
123456789012.dkr.ecr.us-east-1.amazonaws.com/myapp/frontend:v1.0.0

Push the Image​

Push the tagged image to ECR. If you set scanOnPush=true, an image scan runs automatically after the push completes.

❯ docker push \
123456789012.dkr.ecr.us-east-1.amazonaws.com/myapp/frontend:v1.0.0

After the push, you can list the images in the repository via the CLI.

❯ aws ecr describe-images \
--repository-name myapp/frontend
{
"imageDetails": [
{
"registryId": "123456789012",
"repositoryName": "myapp/frontend",
"imageDigest": "sha256:abc123def456...",
"imageTags": [
"v1.0.0"
],
"imageSizeInBytes": 26092648,
"imagePushedAt": "2026-05-14T18:22:58.657000+09:00",
"imageManifestMediaType": "application/vnd.docker.distribution.manifest.v2+json",
"artifactMediaType": "application/vnd.docker.container.image.v1+json",
"imageStatus": "ACTIVE"
}
]
}

Pull the Image​

To pull an ECR image from another environment, authenticate first and then run docker pull. When pulling from ECS or EKS, you can grant permissions via a task role or node IAM role for automatic authentication — but for local or CI environments, you'll need to authenticate manually.

❯ aws ecr get-login-password | \
docker login --username AWS --password-stdin \
123456789012.dkr.ecr.us-east-1.amazonaws.com
Login Succeeded

Once authenticated, pull the image.

❯ docker pull \
123456789012.dkr.ecr.us-east-1.amazonaws.com/myapp/frontend:v1.0.0

Auto-Delete Old Images with Lifecycle Policies​

As images accumulate in ECR, storage costs can grow. Lifecycle policies let you automatically delete images that match certain conditions.

Policies are defined as rules. The example below sets a rule to delete untagged images oldest-first when there are more than 5.

❯ cat << 'EOF' > lifecycle-policy.json
{
"rules": [
{
"rulePriority": 1,
"description": "Keep only 5 untagged images",
"selection": {
"tagStatus": "untagged",
"countType": "imageCountMoreThan",
"countNumber": 5
},
"action": {
"type": "expire"
}
}
]
}
EOF
❯ aws ecr put-lifecycle-policy \
--repository-name myapp/frontend \
--lifecycle-policy-text file://lifecycle-policy.json
{
"registryId": "123456789012",
"repositoryName": "myapp/frontend",
"lifecyclePolicyText": "{\"rules\":[{\"rulePriority\":1,\"description\":\"Keep only 5 untagged images\",\"selection\":{\"tagStatus\":\"untagged\",\"countType\":\"imageCountMoreThan\",\"countNumber\":5},\"action\":{\"type\":\"expire\"}}]}"
}

Clean Up Resources​

To delete the repository, use the delete-repository command. The --force flag is required if images still exist in the repository.

❯ aws ecr delete-repository \
--repository-name myapp/frontend \
--force
{
"repository": {
"repositoryArn": "arn:aws:ecr:us-east-1:123456789012:repository/myapp/frontend",
"registryId": "123456789012",
"repositoryName": "myapp/frontend",
"repositoryUri": "123456789012.dkr.ecr.us-east-1.amazonaws.com/myapp/frontend",
"createdAt": "2026-05-14T18:17:26.708000+09:00",
"imageTagMutability": "IMMUTABLE"
}
}

Summary​

This article covered the core concepts of Amazon ECR and how to create a repository and push and pull images using the AWS CLI. Keep these points in mind as you use ECR in your container workflows:

  • ECR is a fully managed container image registry from AWS with fine-grained access control through IAM
  • It integrates seamlessly with AWS compute services like ECS, EKS, and App Runner, with no data transfer charges within the same region
  • Authenticate the Docker client with an ECR token to push and pull images
  • Enable tag immutability to prevent tag overwrites, and enable scan-on-push to automatically detect vulnerabilities
  • Repository policies let you control things like read-only access from other AWS accounts
  • A pull-through cache reduces your dependency on external registries and their rate limits
  • Set lifecycle policies to auto-delete old images and keep storage costs down