AWS Finally Listens: After 5+ Years, ECR Gets Two Game-Changing Features
The Long Wait Is Over
In late 2025 and early 2026, Amazon Web Services released two of the most requested features in ECR’s history:
- Automatic repository creation on image push (December 19th, 2025)
- Cross-repository layer sharing via blob mounting (January 20th, 2026)
For those of us who have been managing container workflows on AWS, these announcements are nothing short of a miracle. These two features alone transform ECR from “that registry we avoid” to “a genuinely competitive option.”
For over five years, developers have been asking, begging, and practically pleading for these features. The infamous GitHub issues accumulated:
| Feature | Issue | Opened | Upvotes | Wait Time |
|---|---|---|---|---|
| Create on Push | #853 | April 2020 | 700+ | 5+ years |
| Layer Sharing | #531 | October 2019 | 300+ | 6+ years |
Many had lost hope. But AWS finally delivered—on both fronts.
Part 1: Automatic Repository Creation on Push
The Problem
If you’ve ever worked with container registries, you know that the standard workflow is simple:
- Build your image
- Tag it with your registry URL
- Push it
That’s it. Docker Hub, Google Container Registry (GCR), Azure Container Registry (ACR), Quay, Harbor, Artifactory, Nexus—every single major container registry works this way. If the repository doesn’t exist, it gets created automatically.
Except ECR.
With Amazon ECR, before you could push an image, you had to:
- Pre-create the repository using the AWS Console, CLI, CloudFormation, or Terraform
- Configure the repository settings (encryption, lifecycle policies, permissions)
- Then push your image
This might seem like a minor inconvenience, but it created massive headaches in real-world scenarios:
The Developer Experience Nightmare
Consider a development team practicing continuous integration. Every time a developer creates a new microservice, they need to:
- Request a new ECR repository (or have permissions to create one)
- Wait for the infrastructure team to provision it (if they don’t have permissions)
- Update their CI/CD pipeline to reference the new repository
- Finally push their image
Compare this to GCR where you just… push. The repository appears. Done.
CI/CD Pipeline Complexity
CI/CD pipelines became unnecessarily complex. You couldn’t just have a simple docker push command. You needed error handling, repository existence checks, and creation logic wrapped around every push:
# The ECR workaround everyone hated
aws ecr describe-repositories --repository-names "${REPO_NAME}" 2>/dev/null || \
aws ecr create-repository --repository-name "${REPO_NAME}"
docker push "${ECR_URL}/${REPO_NAME}:${TAG}"
This added complexity, potential race conditions, and additional IAM permissions requirements.
Platform Integration Challenges
Modern platforms like Kubernetes, Tanzu Application Platform (RIP), and others often need to push images dynamically. I wrote about this exact challenge back in 2022 in my blog post TAP with ECR – Crossplane and Kyverno to the Rescue, where I detailed the elaborate workarounds we needed to implement just to make Tanzu Application Platform (RIP) work with ECR.
The solution involved:
- Crossplane to dynamically provision ECR repositories as Kubernetes resources
- Kyverno policies to automatically trigger repository creation based on workload definitions
- Complex RBAC and IAM role mappings
It worked, but it was a lot of infrastructure complexity just to achieve what should have been a built-in feature.
The Community Frustration
The comments on the GitHub issue tell the story:
“This is the largest blocker for us in fully transitioning to ECR. Unbelievable it doesn’t exist yet…” — @MichaelErmer, July 2022
“We really need this feature as well, otherwise we simply can’t use ECR.” — @vrabbi (yes, me!), October 2022
“This feature works really well in Artifactory and Nexus… if you are coming from one of these other products where this feature is baked into docker push.” — @sputmayer, December 2021
“Just so you know, this works fine in Google Cloud Container Registry.” — @simonlsk, May 2023
The Solution: Repository Creation Templates with Create on Push
AWS has solved this problem elegantly with Repository Creation Templates that now support a Create on Push applied-for type.
How It Works
The feature works in three key steps:
-
Create a Repository Creation Template: Define the settings you want applied to any new repositories (encryption, lifecycle policies, permissions, tags, etc.)
-
Specify “Create on Push” as an Applied-For Type: This tells ECR to use this template when someone pushes to a repository that doesn’t exist
-
Push Your Images: When you push to a non-existent repository, ECR automatically creates it with your template settings applied
Here’s the workflow visualized:
Developer pushes image to: 123456789.dkr.ecr.us-east-1.amazonaws.com/myapp/frontend:v1.0
|
v
Repository "myapp/frontend" doesn't exist
|
v
ECR checks for matching repository creation template
|
v
Template with prefix "myapp" found with CREATE_ON_PUSH enabled
|
v
Repository created with template settings (encryption, policies, etc.)
|
v
Image pushed successfully!
Template Configuration Options
Repository creation templates give you control over:
| Setting | Description |
|---|---|
| Prefix | Repository namespace prefix (e.g., prod/, myapp/) or ROOT for all |
| Applied For | PULL_THROUGH_CACHE, CREATE_ON_PUSH, or REPLICATION |
| Image Tag Mutability | MUTABLE or IMMUTABLE |
| Encryption | AES-256 (default) or KMS with custom keys |
| Repository Policy | IAM resource-based access control |
| Lifecycle Policy | Automatic image cleanup rules |
| Resource Tags | Metadata for organization and cost tracking |
Part 2: Cross-Repository Layer Sharing (Blob Mounting)
The Problem
ECR’s repository-per-image model created another significant pain point: no layer sharing between repositories.
Container images are built in layers. When you have dozens of microservices all built on the same base image (say, node:18-alpine or your company’s custom base image), those base layers are identical across all your service images.
In most container registries, these common layers are stored once and shared. When you push a new image, the registry recognizes “I already have this layer” and skips the upload.
Not ECR. Every repository was an island. Push the same base layer to 50 different repositories? ECR would happily store 50 copies and charge you for all of them.
The GitHub issue #531, opened in October 2019, captured the frustration:
“Currently ECR doesn’t cache image layers between repositories and with ECR’s model of creating a repo per image this leads to quite poor performance, especially in situations where there are many images being built on a common base-image.” — @jespersoderlund
The impact was significant:
- Slow pushes: Every image push uploaded the full image, even when layers already existed in other repositories
- Increased storage costs: Duplicate layers stored across repositories
- Poor replication performance: Cross-region replication had to transfer duplicate data
- Frustrated platform teams: Managing hundreds of microservices meant dealing with these inefficiencies at scale
The Solution: Blob Mounting
On January 20th, 2026, AWS released blob mounting for ECR. This feature enables cross-repository layer sharing within a registry.
How It Works
When blob mounting is enabled:
- During an image push, ECR checks if the layer already exists in any repository within the same registry
- If found, ECR “mounts” (references) the existing layer instead of storing a duplicate
- The push completes faster, and you don’t pay for duplicate storage
Push image to: myapp/service-a (has layers A, B, C)
|
v
Layer A already exists in myapp/service-b
|
v
ECR mounts existing Layer A (no re-upload needed)
|
v
Layers B and C uploaded normally
|
v
Push completes faster with less storage used
Key Concepts
- Blob mounting only works within the same registry (same account and region)
- Repositories must use identical encryption type and keys
- Blob mounting is not supported for images created via pull through cache
- If you disable blob mounting later, existing mounted layers continue to work
Enabling Blob Mounting
Using the AWS Console
- Open the Amazon ECR console
- Navigate to Private registry > Feature & Settings > Blob mounting
- Click Enable
Using the AWS CLI
aws ecr put-account-setting --name BLOB_MOUNTING --value ENABLED
Using Terraform
The Terraform support is merged and will be available in the next AWS provider release:
resource "aws_ecr_account_setting" "blob_mounting" {
name = "BLOB_MOUNTING"
value = "ENABLED"
}
Getting Started with Create on Push
Using the AWS Console
- Open the Amazon ECR console
- Navigate to Private registry > Repository creation templates
- Click Create template
- Choose A specific prefix or Any prefix in your ECR registry
- For Applied for, select CREATE_ON_PUSH (and optionally
PULL_THROUGH_CACHEandREPLICATION) - Configure your desired settings (encryption, lifecycle policies, etc.)
- Click Create
Using the AWS CLI
Create a template configuration file create-on-push-template.json:
{
"prefix": "ROOT",
"description": "Default template for all repositories created on push",
"appliedFor": ["CREATE_ON_PUSH"],
"imageTagMutability": "MUTABLE",
"encryptionConfiguration": {
"encryptionType": "AES256"
},
"lifecyclePolicy": "{\"rules\":[{\"rulePriority\":1,\"description\":\"Keep last 30 images\",\"selection\":{\"tagStatus\":\"any\",\"countType\":\"imageCountMoreThan\",\"countNumber\":30},\"action\":{\"type\":\"expire\"}}]}"
}
Then apply it:
aws ecr create-repository-creation-template \
--cli-input-json file://create-on-push-template.json
Using Terraform
The aws_ecr_repository_creation_template resource was added in AWS provider version 6.28.0. Here are practical examples:
Basic Create on Push Template
resource "aws_ecr_repository_creation_template" "default" {
prefix = "ROOT"
description = "Default settings for all auto-created repositories"
applied_for = ["CREATE_ON_PUSH"]
image_tag_mutability = "MUTABLE"
encryption_configuration {
encryption_type = "AES256"
}
}
Production Template with Full Configuration
resource "aws_ecr_repository_creation_template" "production" {
prefix = "prod"
description = "Production repositories with strict settings"
applied_for = ["CREATE_ON_PUSH", "REPLICATION"]
image_tag_mutability = "IMMUTABLE"
encryption_configuration {
encryption_type = "KMS"
kms_key = aws_kms_key.ecr.arn
}
resource_tags = {
Environment = "production"
ManagedBy = "terraform"
CostCenter = "platform-team"
}
# Custom IAM role required when using KMS or resource tags
custom_role_arn = aws_iam_role.ecr_template_role.arn
lifecycle_policy = jsonencode({
rules = [
{
rulePriority = 1
description = "Keep last 50 tagged images"
selection = {
tagStatus = "tagged"
tagPrefixList = ["v"]
countType = "imageCountMoreThan"
countNumber = 50
}
action = {
type = "expire"
}
},
{
rulePriority = 2
description = "Expire untagged images older than 7 days"
selection = {
tagStatus = "untagged"
countType = "sinceImagePushed"
countUnit = "days"
countNumber = 7
}
action = {
type = "expire"
}
}
]
})
repository_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Sid = "AllowPull"
Effect = "Allow"
Principal = {
AWS = "arn:aws:iam::${data.aws_caller_identity.current.account_id}:root"
}
Action = [
"ecr:GetDownloadUrlForLayer",
"ecr:BatchGetImage",
"ecr:BatchCheckLayerAvailability"
]
}
]
})
}
# KMS key for repository encryption
resource "aws_kms_key" "ecr" {
description = "KMS key for ECR repository encryption"
deletion_window_in_days = 7
enable_key_rotation = true
}
# IAM role for repository creation template
resource "aws_iam_role" "ecr_template_role" {
name = "ecr-repository-creation-template-role"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Principal = {
Service = "ecr.amazonaws.com"
}
Action = "sts:AssumeRole"
}
]
})
}
resource "aws_iam_role_policy" "ecr_template_policy" {
name = "ecr-template-policy"
role = aws_iam_role.ecr_template_role.id
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Action = [
"ecr:CreateRepository",
"ecr:TagResource",
"ecr:PutLifecyclePolicy",
"ecr:SetRepositoryPolicy"
]
Resource = "*"
},
{
Effect = "Allow"
Action = [
"kms:Encrypt",
"kms:Decrypt",
"kms:GenerateDataKey*"
]
Resource = aws_kms_key.ecr.arn
}
]
})
}
Multiple Environment Templates
locals {
environments = {
dev = {
prefix = "dev"
tag_mutability = "MUTABLE"
encryption_type = "AES256"
image_retention = 10
}
staging = {
prefix = "staging"
tag_mutability = "MUTABLE"
encryption_type = "AES256"
image_retention = 20
}
prod = {
prefix = "prod"
tag_mutability = "IMMUTABLE"
encryption_type = "KMS"
image_retention = 100
}
}
}
resource "aws_ecr_repository_creation_template" "environment" {
for_each = local.environments
prefix = each.value.prefix
description = "${each.key} environment repositories"
applied_for = ["CREATE_ON_PUSH"]
image_tag_mutability = each.value.tag_mutability
encryption_configuration {
encryption_type = each.value.encryption_type
kms_key = each.value.encryption_type == "KMS" ? aws_kms_key.ecr.arn : null
}
custom_role_arn = each.value.encryption_type == "KMS" ? aws_iam_role.ecr_template_role.arn : null
resource_tags = {
Environment = each.key
}
lifecycle_policy = jsonencode({
rules = [
{
rulePriority = 1
description = "Keep last ${each.value.image_retention} images"
selection = {
tagStatus = "any"
countType = "imageCountMoreThan"
countNumber = each.value.image_retention
}
action = {
type = "expire"
}
}
]
})
}
Complete Terraform Configuration: Both Features
Here’s a complete Terraform configuration that enables both new features:
# Enable blob mounting for cross-repository layer sharing
resource "aws_ecr_account_setting" "blob_mounting" {
name = "BLOB_MOUNTING"
value = "ENABLED"
}
# Create a default repository creation template for create-on-push
resource "aws_ecr_repository_creation_template" "default" {
prefix = "ROOT"
description = "Default settings for all auto-created repositories"
applied_for = ["CREATE_ON_PUSH", "PULL_THROUGH_CACHE", "REPLICATION"]
image_tag_mutability = "MUTABLE"
encryption_configuration {
encryption_type = "AES256"
}
lifecycle_policy = jsonencode({
rules = [
{
rulePriority = 1
description = "Keep last 50 images"
selection = {
tagStatus = "any"
countType = "imageCountMoreThan"
countNumber = 50
}
action = {
type = "expire"
}
}
]
})
}
IAM Permissions Required
To create and manage repository creation templates, ensure your IAM principal has these permissions:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"ecr:CreateRepositoryCreationTemplate",
"ecr:UpdateRepositoryCreationTemplate",
"ecr:DescribeRepositoryCreationTemplates",
"ecr:DeleteRepositoryCreationTemplate",
"ecr:CreateRepository",
"ecr:PutLifecyclePolicy",
"ecr:SetRepositoryPolicy",
"ecr:PutAccountSetting",
"ecr:GetAccountSetting"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": "iam:PassRole",
"Resource": "arn:aws:iam::*:role/ecr-*"
}
]
}
Important Considerations
Template Prefix Matching
Templates are matched based on the most specific prefix. For example:
- A repository named
prod/team/myappwould match a template with prefixprod/teamover one with justprod - Use
ROOTas the prefix to create a catch-all template for repositories that don’t match any other template
Templates Don’t Affect Existing Repositories
Repository creation templates only apply when ECR creates a new repository. Existing repositories are not modified. If you need to update existing repositories, you’ll need to do that separately.
KMS and Tags Require an IAM Role
If your template uses KMS encryption or resource tags, you must specify a customRoleArn. This role is assumed by ECR when creating repositories. Without it, repository creation will fail.
Blob Mounting Encryption Requirements
For blob mounting to work between repositories, they must use identical encryption types and keys. If you have repositories with different encryption configurations, layers cannot be shared between them.
Summary
After more than five and six years of waiting respectively, ECR has finally caught up with every other container registry on the planet. These two features together transform ECR from a clunky, DevOps-hostile service into something genuinely competitive.
What we gained with Create on Push:
- Seamless push workflows—just push, the repository appears
- Consistent repository settings across your organization
- Simplified CI/CD pipelines—no more pre-creation scripts
- Better platform integrations (goodbye Crossplane workarounds!)
- Parity with other major container registries
What we gained with Blob Mounting:
- Faster image pushes by reusing existing layers
- Reduced storage costs by eliminating duplicate layers
- Improved replication performance
- Better efficiency for microservices architectures with shared base images
What’s different from other registries:
- You need to create at least one repository creation template first
- You need to explicitly enable blob mounting at the registry level
- Templates give you more control over default settings than most registries offer
This is exactly what the community asked for, and AWS delivered. For anyone who commented on issues #853 and #531, voted them up, or wrote workarounds like I did—our patience has been rewarded.
Now if you’ll excuse me, I have some Crossplane and Kyverno resources to delete.
Resources
Create on Push
- AWS Documentation: Repository Creation Templates
- AWS Documentation: Creating a Repository Creation Template
- Terraform AWS Provider: aws_ecr_repository_creation_template
- GitHub Issue #853: Repository create on push
Blob Mounting
Related
- My Previous Blog: TAP with ECR – Crossplane and Kyverno to the Rescue — A historical record of the workarounds we needed
Posted on January 2026
