Configure AWS ECR Replication

The aws:ecr/replicationConfiguration:ReplicationConfiguration resource, part of the Pulumi AWS provider, defines registry-level replication rules that automatically copy container images to destination regions and accounts. This guide focuses on two capabilities: single and multi-region replication, and repository filtering by prefix.

Replication configuration operates at the registry level and applies to existing ECR repositories. The examples are intentionally small. Combine them with your own repository naming conventions and multi-account strategies.

Replicate all repositories to a single region

Teams deploying multi-region applications need container images available in multiple AWS regions to reduce latency and improve availability.

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

const current = aws.getCallerIdentity({});
const example = aws.getRegions({});
const exampleReplicationConfiguration = new aws.ecr.ReplicationConfiguration("example", {replicationConfiguration: {
    rules: [{
        destinations: [{
            region: example.then(example => example.names?.[0]),
            registryId: current.then(current => current.accountId),
        }],
    }],
}});
import pulumi
import pulumi_aws as aws

current = aws.get_caller_identity()
example = aws.get_regions()
example_replication_configuration = aws.ecr.ReplicationConfiguration("example", replication_configuration={
    "rules": [{
        "destinations": [{
            "region": example.names[0],
            "registry_id": current.account_id,
        }],
    }],
})
package main

import (
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws"
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/ecr"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		current, err := aws.GetCallerIdentity(ctx, &aws.GetCallerIdentityArgs{}, nil)
		if err != nil {
			return err
		}
		example, err := aws.GetRegions(ctx, &aws.GetRegionsArgs{}, nil)
		if err != nil {
			return err
		}
		_, err = ecr.NewReplicationConfiguration(ctx, "example", &ecr.ReplicationConfigurationArgs{
			ReplicationConfiguration: &ecr.ReplicationConfigurationReplicationConfigurationArgs{
				Rules: ecr.ReplicationConfigurationReplicationConfigurationRuleArray{
					&ecr.ReplicationConfigurationReplicationConfigurationRuleArgs{
						Destinations: ecr.ReplicationConfigurationReplicationConfigurationRuleDestinationArray{
							&ecr.ReplicationConfigurationReplicationConfigurationRuleDestinationArgs{
								Region:     pulumi.String(example.Names[0]),
								RegistryId: pulumi.String(current.AccountId),
							},
						},
					},
				},
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;

return await Deployment.RunAsync(() => 
{
    var current = Aws.GetCallerIdentity.Invoke();

    var example = Aws.GetRegions.Invoke();

    var exampleReplicationConfiguration = new Aws.Ecr.ReplicationConfiguration("example", new()
    {
        ReplicationConfigurationDetails = new Aws.Ecr.Inputs.ReplicationConfigurationReplicationConfigurationArgs
        {
            Rules = new[]
            {
                new Aws.Ecr.Inputs.ReplicationConfigurationReplicationConfigurationRuleArgs
                {
                    Destinations = new[]
                    {
                        new Aws.Ecr.Inputs.ReplicationConfigurationReplicationConfigurationRuleDestinationArgs
                        {
                            Region = example.Apply(getRegionsResult => getRegionsResult.Names[0]),
                            RegistryId = current.Apply(getCallerIdentityResult => getCallerIdentityResult.AccountId),
                        },
                    },
                },
            },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.AwsFunctions;
import com.pulumi.aws.inputs.GetCallerIdentityArgs;
import com.pulumi.aws.inputs.GetRegionsArgs;
import com.pulumi.aws.ecr.ReplicationConfiguration;
import com.pulumi.aws.ecr.ReplicationConfigurationArgs;
import com.pulumi.aws.ecr.inputs.ReplicationConfigurationReplicationConfigurationArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        final var current = AwsFunctions.getCallerIdentity(GetCallerIdentityArgs.builder()
            .build());

        final var example = AwsFunctions.getRegions(GetRegionsArgs.builder()
            .build());

        var exampleReplicationConfiguration = new ReplicationConfiguration("exampleReplicationConfiguration", ReplicationConfigurationArgs.builder()
            .replicationConfiguration(ReplicationConfigurationReplicationConfigurationArgs.builder()
                .rules(ReplicationConfigurationReplicationConfigurationRuleArgs.builder()
                    .destinations(ReplicationConfigurationReplicationConfigurationRuleDestinationArgs.builder()
                        .region(example.names()[0])
                        .registryId(current.accountId())
                        .build())
                    .build())
                .build())
            .build());

    }
}
resources:
  exampleReplicationConfiguration:
    type: aws:ecr:ReplicationConfiguration
    name: example
    properties:
      replicationConfiguration:
        rules:
          - destinations:
              - region: ${example.names[0]}
                registryId: ${current.accountId}
variables:
  current:
    fn::invoke:
      function: aws:getCallerIdentity
      arguments: {}
  example:
    fn::invoke:
      function: aws:getRegions
      arguments: {}

When you push an image to any repository in the source registry, ECR automatically replicates it to the destination region. The replicationConfiguration property defines rules with destinations arrays. Each destination specifies a region and registryId (the AWS account). Here, images replicate to the first available region in the current account.

Replicate to multiple regions simultaneously

Global applications often need images in several regions at once. A single rule can target multiple destinations.

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

const current = aws.getCallerIdentity({});
const example = aws.getRegions({});
const exampleReplicationConfiguration = new aws.ecr.ReplicationConfiguration("example", {replicationConfiguration: {
    rules: [{
        destinations: [
            {
                region: example.then(example => example.names?.[0]),
                registryId: current.then(current => current.accountId),
            },
            {
                region: example.then(example => example.names?.[1]),
                registryId: current.then(current => current.accountId),
            },
        ],
    }],
}});
import pulumi
import pulumi_aws as aws

current = aws.get_caller_identity()
example = aws.get_regions()
example_replication_configuration = aws.ecr.ReplicationConfiguration("example", replication_configuration={
    "rules": [{
        "destinations": [
            {
                "region": example.names[0],
                "registry_id": current.account_id,
            },
            {
                "region": example.names[1],
                "registry_id": current.account_id,
            },
        ],
    }],
})
package main

import (
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws"
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/ecr"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		current, err := aws.GetCallerIdentity(ctx, &aws.GetCallerIdentityArgs{}, nil)
		if err != nil {
			return err
		}
		example, err := aws.GetRegions(ctx, &aws.GetRegionsArgs{}, nil)
		if err != nil {
			return err
		}
		_, err = ecr.NewReplicationConfiguration(ctx, "example", &ecr.ReplicationConfigurationArgs{
			ReplicationConfiguration: &ecr.ReplicationConfigurationReplicationConfigurationArgs{
				Rules: ecr.ReplicationConfigurationReplicationConfigurationRuleArray{
					&ecr.ReplicationConfigurationReplicationConfigurationRuleArgs{
						Destinations: ecr.ReplicationConfigurationReplicationConfigurationRuleDestinationArray{
							&ecr.ReplicationConfigurationReplicationConfigurationRuleDestinationArgs{
								Region:     pulumi.String(example.Names[0]),
								RegistryId: pulumi.String(current.AccountId),
							},
							&ecr.ReplicationConfigurationReplicationConfigurationRuleDestinationArgs{
								Region:     pulumi.String(example.Names[1]),
								RegistryId: pulumi.String(current.AccountId),
							},
						},
					},
				},
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;

return await Deployment.RunAsync(() => 
{
    var current = Aws.GetCallerIdentity.Invoke();

    var example = Aws.GetRegions.Invoke();

    var exampleReplicationConfiguration = new Aws.Ecr.ReplicationConfiguration("example", new()
    {
        ReplicationConfigurationDetails = new Aws.Ecr.Inputs.ReplicationConfigurationReplicationConfigurationArgs
        {
            Rules = new[]
            {
                new Aws.Ecr.Inputs.ReplicationConfigurationReplicationConfigurationRuleArgs
                {
                    Destinations = new[]
                    {
                        new Aws.Ecr.Inputs.ReplicationConfigurationReplicationConfigurationRuleDestinationArgs
                        {
                            Region = example.Apply(getRegionsResult => getRegionsResult.Names[0]),
                            RegistryId = current.Apply(getCallerIdentityResult => getCallerIdentityResult.AccountId),
                        },
                        new Aws.Ecr.Inputs.ReplicationConfigurationReplicationConfigurationRuleDestinationArgs
                        {
                            Region = example.Apply(getRegionsResult => getRegionsResult.Names[1]),
                            RegistryId = current.Apply(getCallerIdentityResult => getCallerIdentityResult.AccountId),
                        },
                    },
                },
            },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.AwsFunctions;
import com.pulumi.aws.inputs.GetCallerIdentityArgs;
import com.pulumi.aws.inputs.GetRegionsArgs;
import com.pulumi.aws.ecr.ReplicationConfiguration;
import com.pulumi.aws.ecr.ReplicationConfigurationArgs;
import com.pulumi.aws.ecr.inputs.ReplicationConfigurationReplicationConfigurationArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        final var current = AwsFunctions.getCallerIdentity(GetCallerIdentityArgs.builder()
            .build());

        final var example = AwsFunctions.getRegions(GetRegionsArgs.builder()
            .build());

        var exampleReplicationConfiguration = new ReplicationConfiguration("exampleReplicationConfiguration", ReplicationConfigurationArgs.builder()
            .replicationConfiguration(ReplicationConfigurationReplicationConfigurationArgs.builder()
                .rules(ReplicationConfigurationReplicationConfigurationRuleArgs.builder()
                    .destinations(                    
                        ReplicationConfigurationReplicationConfigurationRuleDestinationArgs.builder()
                            .region(example.names()[0])
                            .registryId(current.accountId())
                            .build(),
                        ReplicationConfigurationReplicationConfigurationRuleDestinationArgs.builder()
                            .region(example.names()[1])
                            .registryId(current.accountId())
                            .build())
                    .build())
                .build())
            .build());

    }
}
resources:
  exampleReplicationConfiguration:
    type: aws:ecr:ReplicationConfiguration
    name: example
    properties:
      replicationConfiguration:
        rules:
          - destinations:
              - region: ${example.names[0]}
                registryId: ${current.accountId}
              - region: ${example.names[1]}
                registryId: ${current.accountId}
variables:
  current:
    fn::invoke:
      function: aws:getCallerIdentity
      arguments: {}
  example:
    fn::invoke:
      function: aws:getRegions
      arguments: {}

The destinations array can include multiple regions. ECR replicates each image push to all specified destinations in parallel, ensuring consistent availability across deployment regions. This extends the basic example by adding a second destination region.

Replicate only repositories matching a prefix

Organizations with many repositories often want selective replication to control costs and reduce data transfer.

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

const current = aws.getCallerIdentity({});
const example = aws.getRegions({});
const exampleReplicationConfiguration = new aws.ecr.ReplicationConfiguration("example", {replicationConfiguration: {
    rules: [{
        destinations: [{
            region: example.then(example => example.names?.[0]),
            registryId: current.then(current => current.accountId),
        }],
        repositoryFilters: [{
            filter: "prod-microservice",
            filterType: "PREFIX_MATCH",
        }],
    }],
}});
import pulumi
import pulumi_aws as aws

current = aws.get_caller_identity()
example = aws.get_regions()
example_replication_configuration = aws.ecr.ReplicationConfiguration("example", replication_configuration={
    "rules": [{
        "destinations": [{
            "region": example.names[0],
            "registry_id": current.account_id,
        }],
        "repository_filters": [{
            "filter": "prod-microservice",
            "filter_type": "PREFIX_MATCH",
        }],
    }],
})
package main

import (
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws"
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/ecr"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		current, err := aws.GetCallerIdentity(ctx, &aws.GetCallerIdentityArgs{}, nil)
		if err != nil {
			return err
		}
		example, err := aws.GetRegions(ctx, &aws.GetRegionsArgs{}, nil)
		if err != nil {
			return err
		}
		_, err = ecr.NewReplicationConfiguration(ctx, "example", &ecr.ReplicationConfigurationArgs{
			ReplicationConfiguration: &ecr.ReplicationConfigurationReplicationConfigurationArgs{
				Rules: ecr.ReplicationConfigurationReplicationConfigurationRuleArray{
					&ecr.ReplicationConfigurationReplicationConfigurationRuleArgs{
						Destinations: ecr.ReplicationConfigurationReplicationConfigurationRuleDestinationArray{
							&ecr.ReplicationConfigurationReplicationConfigurationRuleDestinationArgs{
								Region:     pulumi.String(example.Names[0]),
								RegistryId: pulumi.String(current.AccountId),
							},
						},
						RepositoryFilters: ecr.ReplicationConfigurationReplicationConfigurationRuleRepositoryFilterArray{
							&ecr.ReplicationConfigurationReplicationConfigurationRuleRepositoryFilterArgs{
								Filter:     pulumi.String("prod-microservice"),
								FilterType: pulumi.String("PREFIX_MATCH"),
							},
						},
					},
				},
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;

return await Deployment.RunAsync(() => 
{
    var current = Aws.GetCallerIdentity.Invoke();

    var example = Aws.GetRegions.Invoke();

    var exampleReplicationConfiguration = new Aws.Ecr.ReplicationConfiguration("example", new()
    {
        ReplicationConfigurationDetails = new Aws.Ecr.Inputs.ReplicationConfigurationReplicationConfigurationArgs
        {
            Rules = new[]
            {
                new Aws.Ecr.Inputs.ReplicationConfigurationReplicationConfigurationRuleArgs
                {
                    Destinations = new[]
                    {
                        new Aws.Ecr.Inputs.ReplicationConfigurationReplicationConfigurationRuleDestinationArgs
                        {
                            Region = example.Apply(getRegionsResult => getRegionsResult.Names[0]),
                            RegistryId = current.Apply(getCallerIdentityResult => getCallerIdentityResult.AccountId),
                        },
                    },
                    RepositoryFilters = new[]
                    {
                        new Aws.Ecr.Inputs.ReplicationConfigurationReplicationConfigurationRuleRepositoryFilterArgs
                        {
                            Filter = "prod-microservice",
                            FilterType = "PREFIX_MATCH",
                        },
                    },
                },
            },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.AwsFunctions;
import com.pulumi.aws.inputs.GetCallerIdentityArgs;
import com.pulumi.aws.inputs.GetRegionsArgs;
import com.pulumi.aws.ecr.ReplicationConfiguration;
import com.pulumi.aws.ecr.ReplicationConfigurationArgs;
import com.pulumi.aws.ecr.inputs.ReplicationConfigurationReplicationConfigurationArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        final var current = AwsFunctions.getCallerIdentity(GetCallerIdentityArgs.builder()
            .build());

        final var example = AwsFunctions.getRegions(GetRegionsArgs.builder()
            .build());

        var exampleReplicationConfiguration = new ReplicationConfiguration("exampleReplicationConfiguration", ReplicationConfigurationArgs.builder()
            .replicationConfiguration(ReplicationConfigurationReplicationConfigurationArgs.builder()
                .rules(ReplicationConfigurationReplicationConfigurationRuleArgs.builder()
                    .destinations(ReplicationConfigurationReplicationConfigurationRuleDestinationArgs.builder()
                        .region(example.names()[0])
                        .registryId(current.accountId())
                        .build())
                    .repositoryFilters(ReplicationConfigurationReplicationConfigurationRuleRepositoryFilterArgs.builder()
                        .filter("prod-microservice")
                        .filterType("PREFIX_MATCH")
                        .build())
                    .build())
                .build())
            .build());

    }
}
resources:
  exampleReplicationConfiguration:
    type: aws:ecr:ReplicationConfiguration
    name: example
    properties:
      replicationConfiguration:
        rules:
          - destinations:
              - region: ${example.names[0]}
                registryId: ${current.accountId}
            repositoryFilters:
              - filter: prod-microservice
                filterType: PREFIX_MATCH
variables:
  current:
    fn::invoke:
      function: aws:getCallerIdentity
      arguments: {}
  example:
    fn::invoke:
      function: aws:getRegions
      arguments: {}

The repositoryFilters property limits replication to repositories matching specific patterns. The filter property sets the prefix to match (e.g., “prod-microservice”), and filterType specifies how to match (PREFIX_MATCH checks if repository names start with the filter string). Only repositories matching the filter replicate to destinations.

Beyond these examples

These snippets focus on specific replication configuration features: single and multi-region replication, and repository filtering by prefix. They’re intentionally minimal rather than full registry management solutions.

The examples assume pre-existing infrastructure such as ECR repositories in the source registry. They focus on configuring replication rules rather than provisioning repositories or managing cross-account access.

To keep things focused, common replication patterns are omitted, including:

  • Cross-account replication (different registryId values)
  • Advanced filter types beyond PREFIX_MATCH
  • Replication to multiple accounts simultaneously
  • Replication rule ordering and priority

These omissions are intentional: the goal is to illustrate how replication rules are wired, not provide drop-in registry modules. See the ECR ReplicationConfiguration resource reference for all available configuration options.

Let's configure AWS ECR Replication

Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.

Try Pulumi Cloud for FREE

Frequently Asked Questions

Replication Setup
How do I replicate ECR images to multiple regions?
Add multiple destination objects in the destinations array within a rule. Each destination specifies a region and registryId, as shown in the Multiple Region Usage example.
Can I replicate to the same account in different regions?
Yes, the examples demonstrate replicating to different regions within the same account by using the current account ID for each destination’s registryId.
Repository Filtering
How do I selectively replicate only certain repositories?
Use repositoryFilters in your replication rule with a filter string and filterType. The example shows PREFIX_MATCH to replicate repositories matching a prefix like “prod-microservice”.
What does PREFIX_MATCH filter type do?
PREFIX_MATCH replicates repositories whose names start with the specified filter string. For example, a filter of “prod-microservice” would match repositories like “prod-microservice-api” and “prod-microservice-web”.
Import & Management
How do I import an existing ECR replication configuration?
Use pulumi import with the registry ID: pulumi import aws:ecr/replicationConfiguration:ReplicationConfiguration service 012345678912

Using a different cloud?

Explore containers guides for other cloud providers: