The aws:elasticache/replicationGroup:ReplicationGroup resource, part of the Pulumi AWS provider, defines an ElastiCache replication group: a Redis or Valkey cluster with primary and replica nodes, supporting both single-shard and multi-shard (cluster mode) topologies. This guide focuses on four capabilities: single-shard clusters with automatic failover, multi-shard cluster mode for horizontal scaling, availability zone placement and keyspace control, and log delivery and authentication.
Replication groups run in VPC subnet groups with security groups, and may reference parameter groups, CloudWatch log groups, or Kinesis Firehose streams. The examples are intentionally small. Combine them with your own VPC infrastructure, parameter groups, and monitoring targets.
Create a single-shard cluster with read replicas
Most Redis deployments begin with a single shard containing a primary node and one or more read replicas for high availability. This configuration provides automatic failover without the complexity of data sharding.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const example = new aws.elasticache.ReplicationGroup("example", {
automaticFailoverEnabled: true,
preferredCacheClusterAzs: [
"us-west-2a",
"us-west-2b",
],
replicationGroupId: "tf-rep-group-1",
description: "example description",
nodeType: "cache.m4.large",
numCacheClusters: 2,
parameterGroupName: "default.redis3.2",
port: 6379,
});
import pulumi
import pulumi_aws as aws
example = aws.elasticache.ReplicationGroup("example",
automatic_failover_enabled=True,
preferred_cache_cluster_azs=[
"us-west-2a",
"us-west-2b",
],
replication_group_id="tf-rep-group-1",
description="example description",
node_type="cache.m4.large",
num_cache_clusters=2,
parameter_group_name="default.redis3.2",
port=6379)
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/elasticache"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := elasticache.NewReplicationGroup(ctx, "example", &elasticache.ReplicationGroupArgs{
AutomaticFailoverEnabled: pulumi.Bool(true),
PreferredCacheClusterAzs: pulumi.StringArray{
pulumi.String("us-west-2a"),
pulumi.String("us-west-2b"),
},
ReplicationGroupId: pulumi.String("tf-rep-group-1"),
Description: pulumi.String("example description"),
NodeType: pulumi.String("cache.m4.large"),
NumCacheClusters: pulumi.Int(2),
ParameterGroupName: pulumi.String("default.redis3.2"),
Port: pulumi.Int(6379),
})
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 example = new Aws.ElastiCache.ReplicationGroup("example", new()
{
AutomaticFailoverEnabled = true,
PreferredCacheClusterAzs = new[]
{
"us-west-2a",
"us-west-2b",
},
ReplicationGroupId = "tf-rep-group-1",
Description = "example description",
NodeType = "cache.m4.large",
NumCacheClusters = 2,
ParameterGroupName = "default.redis3.2",
Port = 6379,
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.elasticache.ReplicationGroup;
import com.pulumi.aws.elasticache.ReplicationGroupArgs;
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) {
var example = new ReplicationGroup("example", ReplicationGroupArgs.builder()
.automaticFailoverEnabled(true)
.preferredCacheClusterAzs(
"us-west-2a",
"us-west-2b")
.replicationGroupId("tf-rep-group-1")
.description("example description")
.nodeType("cache.m4.large")
.numCacheClusters(2)
.parameterGroupName("default.redis3.2")
.port(6379)
.build());
}
}
resources:
example:
type: aws:elasticache:ReplicationGroup
properties:
automaticFailoverEnabled: true
preferredCacheClusterAzs:
- us-west-2a
- us-west-2b
replicationGroupId: tf-rep-group-1
description: example description
nodeType: cache.m4.large
numCacheClusters: 2
parameterGroupName: default.redis3.2
port: 6379
When the primary fails, ElastiCache automatically promotes a replica to primary. The automaticFailoverEnabled property enables this behavior, and numCacheClusters sets the total count (primary plus replicas). The preferredCacheClusterAzs list controls where nodes are placed; the first zone gets the primary. The parameterGroupName must reference a parameter group compatible with your engine version.
Enable cluster mode for data sharding
Applications that need to scale beyond a single shard’s capacity use cluster mode to distribute data across multiple node groups. Each shard has its own primary and replicas.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const baz = new aws.elasticache.ReplicationGroup("baz", {
replicationGroupId: "tf-redis-cluster",
description: "example description",
nodeType: "cache.t2.small",
port: 6379,
parameterGroupName: "default.redis3.2.cluster.on",
automaticFailoverEnabled: true,
numNodeGroups: 2,
replicasPerNodeGroup: 1,
});
import pulumi
import pulumi_aws as aws
baz = aws.elasticache.ReplicationGroup("baz",
replication_group_id="tf-redis-cluster",
description="example description",
node_type="cache.t2.small",
port=6379,
parameter_group_name="default.redis3.2.cluster.on",
automatic_failover_enabled=True,
num_node_groups=2,
replicas_per_node_group=1)
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/elasticache"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := elasticache.NewReplicationGroup(ctx, "baz", &elasticache.ReplicationGroupArgs{
ReplicationGroupId: pulumi.String("tf-redis-cluster"),
Description: pulumi.String("example description"),
NodeType: pulumi.String("cache.t2.small"),
Port: pulumi.Int(6379),
ParameterGroupName: pulumi.String("default.redis3.2.cluster.on"),
AutomaticFailoverEnabled: pulumi.Bool(true),
NumNodeGroups: pulumi.Int(2),
ReplicasPerNodeGroup: pulumi.Int(1),
})
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 baz = new Aws.ElastiCache.ReplicationGroup("baz", new()
{
ReplicationGroupId = "tf-redis-cluster",
Description = "example description",
NodeType = "cache.t2.small",
Port = 6379,
ParameterGroupName = "default.redis3.2.cluster.on",
AutomaticFailoverEnabled = true,
NumNodeGroups = 2,
ReplicasPerNodeGroup = 1,
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.elasticache.ReplicationGroup;
import com.pulumi.aws.elasticache.ReplicationGroupArgs;
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) {
var baz = new ReplicationGroup("baz", ReplicationGroupArgs.builder()
.replicationGroupId("tf-redis-cluster")
.description("example description")
.nodeType("cache.t2.small")
.port(6379)
.parameterGroupName("default.redis3.2.cluster.on")
.automaticFailoverEnabled(true)
.numNodeGroups(2)
.replicasPerNodeGroup(1)
.build());
}
}
resources:
baz:
type: aws:elasticache:ReplicationGroup
properties:
replicationGroupId: tf-redis-cluster
description: example description
nodeType: cache.t2.small
port: 6379
parameterGroupName: default.redis3.2.cluster.on
automaticFailoverEnabled: true
numNodeGroups: 2
replicasPerNodeGroup: 1
In cluster mode, data is partitioned across shards using consistent hashing. The numNodeGroups property sets the shard count, and replicasPerNodeGroup controls how many read replicas each shard has. The parameterGroupName must reference a parameter group with cluster-enabled set to true (parameter groups ending in .cluster.on). Automatic failover is required for cluster mode.
Control shard placement and keyspace distribution
When you need precise control over where shards run and how keys are distributed, you can specify availability zones and slot ranges for each node group.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const example = new aws.elasticache.ReplicationGroup("example", {
replicationGroupId: "tf-redis-cluster",
description: "example description",
nodeType: "cache.t2.small",
port: 6379,
parameterGroupName: "default.redis3.2.cluster.on",
automaticFailoverEnabled: true,
numNodeGroups: 2,
nodeGroupConfigurations: [
{
nodeGroupId: "0001",
primaryAvailabilityZone: "us-west-2a",
replicaAvailabilityZones: ["us-west-2b"],
replicaCount: 1,
slots: "0-8191",
},
{
nodeGroupId: "0002",
primaryAvailabilityZone: "us-west-2b",
replicaAvailabilityZones: ["us-west-2a"],
replicaCount: 1,
slots: "8192-16383",
},
],
});
import pulumi
import pulumi_aws as aws
example = aws.elasticache.ReplicationGroup("example",
replication_group_id="tf-redis-cluster",
description="example description",
node_type="cache.t2.small",
port=6379,
parameter_group_name="default.redis3.2.cluster.on",
automatic_failover_enabled=True,
num_node_groups=2,
node_group_configurations=[
{
"node_group_id": "0001",
"primary_availability_zone": "us-west-2a",
"replica_availability_zones": ["us-west-2b"],
"replica_count": 1,
"slots": "0-8191",
},
{
"node_group_id": "0002",
"primary_availability_zone": "us-west-2b",
"replica_availability_zones": ["us-west-2a"],
"replica_count": 1,
"slots": "8192-16383",
},
])
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/elasticache"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := elasticache.NewReplicationGroup(ctx, "example", &elasticache.ReplicationGroupArgs{
ReplicationGroupId: pulumi.String("tf-redis-cluster"),
Description: pulumi.String("example description"),
NodeType: pulumi.String("cache.t2.small"),
Port: pulumi.Int(6379),
ParameterGroupName: pulumi.String("default.redis3.2.cluster.on"),
AutomaticFailoverEnabled: pulumi.Bool(true),
NumNodeGroups: pulumi.Int(2),
NodeGroupConfigurations: elasticache.ReplicationGroupNodeGroupConfigurationArray{
&elasticache.ReplicationGroupNodeGroupConfigurationArgs{
NodeGroupId: pulumi.String("0001"),
PrimaryAvailabilityZone: pulumi.String("us-west-2a"),
ReplicaAvailabilityZones: pulumi.StringArray{
pulumi.String("us-west-2b"),
},
ReplicaCount: pulumi.Int(1),
Slots: pulumi.String("0-8191"),
},
&elasticache.ReplicationGroupNodeGroupConfigurationArgs{
NodeGroupId: pulumi.String("0002"),
PrimaryAvailabilityZone: pulumi.String("us-west-2b"),
ReplicaAvailabilityZones: pulumi.StringArray{
pulumi.String("us-west-2a"),
},
ReplicaCount: pulumi.Int(1),
Slots: pulumi.String("8192-16383"),
},
},
})
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 example = new Aws.ElastiCache.ReplicationGroup("example", new()
{
ReplicationGroupId = "tf-redis-cluster",
Description = "example description",
NodeType = "cache.t2.small",
Port = 6379,
ParameterGroupName = "default.redis3.2.cluster.on",
AutomaticFailoverEnabled = true,
NumNodeGroups = 2,
NodeGroupConfigurations = new[]
{
new Aws.ElastiCache.Inputs.ReplicationGroupNodeGroupConfigurationArgs
{
NodeGroupId = "0001",
PrimaryAvailabilityZone = "us-west-2a",
ReplicaAvailabilityZones = new[]
{
"us-west-2b",
},
ReplicaCount = 1,
Slots = "0-8191",
},
new Aws.ElastiCache.Inputs.ReplicationGroupNodeGroupConfigurationArgs
{
NodeGroupId = "0002",
PrimaryAvailabilityZone = "us-west-2b",
ReplicaAvailabilityZones = new[]
{
"us-west-2a",
},
ReplicaCount = 1,
Slots = "8192-16383",
},
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.elasticache.ReplicationGroup;
import com.pulumi.aws.elasticache.ReplicationGroupArgs;
import com.pulumi.aws.elasticache.inputs.ReplicationGroupNodeGroupConfigurationArgs;
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) {
var example = new ReplicationGroup("example", ReplicationGroupArgs.builder()
.replicationGroupId("tf-redis-cluster")
.description("example description")
.nodeType("cache.t2.small")
.port(6379)
.parameterGroupName("default.redis3.2.cluster.on")
.automaticFailoverEnabled(true)
.numNodeGroups(2)
.nodeGroupConfigurations(
ReplicationGroupNodeGroupConfigurationArgs.builder()
.nodeGroupId("0001")
.primaryAvailabilityZone("us-west-2a")
.replicaAvailabilityZones("us-west-2b")
.replicaCount(1)
.slots("0-8191")
.build(),
ReplicationGroupNodeGroupConfigurationArgs.builder()
.nodeGroupId("0002")
.primaryAvailabilityZone("us-west-2b")
.replicaAvailabilityZones("us-west-2a")
.replicaCount(1)
.slots("8192-16383")
.build())
.build());
}
}
resources:
example:
type: aws:elasticache:ReplicationGroup
properties:
replicationGroupId: tf-redis-cluster
description: example description
nodeType: cache.t2.small
port: 6379
parameterGroupName: default.redis3.2.cluster.on
automaticFailoverEnabled: true
numNodeGroups: 2
nodeGroupConfigurations:
- nodeGroupId: '0001'
primaryAvailabilityZone: us-west-2a
replicaAvailabilityZones:
- us-west-2b
replicaCount: 1
slots: 0-8191
- nodeGroupId: '0002'
primaryAvailabilityZone: us-west-2b
replicaAvailabilityZones:
- us-west-2a
replicaCount: 1
slots: 8192-16383
The nodeGroupConfigurations array lets you define each shard explicitly. The nodeGroupId identifies the shard, primaryAvailabilityZone and replicaAvailabilityZones control placement, and slots defines the keyspace range (0-16383 total). This configuration extends cluster mode by pinning shards to specific zones and defining how keys map to shards.
Stream logs to CloudWatch and Kinesis Firehose
For debugging and compliance, you can stream Redis slow logs and engine logs to CloudWatch Logs or Kinesis Firehose for analysis and archival.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const test = new aws.elasticache.ReplicationGroup("test", {
replicationGroupId: "myreplicaciongroup",
description: "test description",
nodeType: "cache.t3.small",
port: 6379,
applyImmediately: true,
autoMinorVersionUpgrade: false,
maintenanceWindow: "tue:06:30-tue:07:30",
snapshotWindow: "01:00-02:00",
logDeliveryConfigurations: [
{
destination: example.name,
destinationType: "cloudwatch-logs",
logFormat: "text",
logType: "slow-log",
},
{
destination: exampleAwsKinesisFirehoseDeliveryStream.name,
destinationType: "kinesis-firehose",
logFormat: "json",
logType: "engine-log",
},
],
});
import pulumi
import pulumi_aws as aws
test = aws.elasticache.ReplicationGroup("test",
replication_group_id="myreplicaciongroup",
description="test description",
node_type="cache.t3.small",
port=6379,
apply_immediately=True,
auto_minor_version_upgrade=False,
maintenance_window="tue:06:30-tue:07:30",
snapshot_window="01:00-02:00",
log_delivery_configurations=[
{
"destination": example["name"],
"destination_type": "cloudwatch-logs",
"log_format": "text",
"log_type": "slow-log",
},
{
"destination": example_aws_kinesis_firehose_delivery_stream["name"],
"destination_type": "kinesis-firehose",
"log_format": "json",
"log_type": "engine-log",
},
])
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/elasticache"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := elasticache.NewReplicationGroup(ctx, "test", &elasticache.ReplicationGroupArgs{
ReplicationGroupId: pulumi.String("myreplicaciongroup"),
Description: pulumi.String("test description"),
NodeType: pulumi.String("cache.t3.small"),
Port: pulumi.Int(6379),
ApplyImmediately: pulumi.Bool(true),
AutoMinorVersionUpgrade: pulumi.Bool(false),
MaintenanceWindow: pulumi.String("tue:06:30-tue:07:30"),
SnapshotWindow: pulumi.String("01:00-02:00"),
LogDeliveryConfigurations: elasticache.ReplicationGroupLogDeliveryConfigurationArray{
&elasticache.ReplicationGroupLogDeliveryConfigurationArgs{
Destination: pulumi.Any(example.Name),
DestinationType: pulumi.String("cloudwatch-logs"),
LogFormat: pulumi.String("text"),
LogType: pulumi.String("slow-log"),
},
&elasticache.ReplicationGroupLogDeliveryConfigurationArgs{
Destination: pulumi.Any(exampleAwsKinesisFirehoseDeliveryStream.Name),
DestinationType: pulumi.String("kinesis-firehose"),
LogFormat: pulumi.String("json"),
LogType: pulumi.String("engine-log"),
},
},
})
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 test = new Aws.ElastiCache.ReplicationGroup("test", new()
{
ReplicationGroupId = "myreplicaciongroup",
Description = "test description",
NodeType = "cache.t3.small",
Port = 6379,
ApplyImmediately = true,
AutoMinorVersionUpgrade = false,
MaintenanceWindow = "tue:06:30-tue:07:30",
SnapshotWindow = "01:00-02:00",
LogDeliveryConfigurations = new[]
{
new Aws.ElastiCache.Inputs.ReplicationGroupLogDeliveryConfigurationArgs
{
Destination = example.Name,
DestinationType = "cloudwatch-logs",
LogFormat = "text",
LogType = "slow-log",
},
new Aws.ElastiCache.Inputs.ReplicationGroupLogDeliveryConfigurationArgs
{
Destination = exampleAwsKinesisFirehoseDeliveryStream.Name,
DestinationType = "kinesis-firehose",
LogFormat = "json",
LogType = "engine-log",
},
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.elasticache.ReplicationGroup;
import com.pulumi.aws.elasticache.ReplicationGroupArgs;
import com.pulumi.aws.elasticache.inputs.ReplicationGroupLogDeliveryConfigurationArgs;
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) {
var test = new ReplicationGroup("test", ReplicationGroupArgs.builder()
.replicationGroupId("myreplicaciongroup")
.description("test description")
.nodeType("cache.t3.small")
.port(6379)
.applyImmediately(true)
.autoMinorVersionUpgrade(false)
.maintenanceWindow("tue:06:30-tue:07:30")
.snapshotWindow("01:00-02:00")
.logDeliveryConfigurations(
ReplicationGroupLogDeliveryConfigurationArgs.builder()
.destination(example.name())
.destinationType("cloudwatch-logs")
.logFormat("text")
.logType("slow-log")
.build(),
ReplicationGroupLogDeliveryConfigurationArgs.builder()
.destination(exampleAwsKinesisFirehoseDeliveryStream.name())
.destinationType("kinesis-firehose")
.logFormat("json")
.logType("engine-log")
.build())
.build());
}
}
resources:
test:
type: aws:elasticache:ReplicationGroup
properties:
replicationGroupId: myreplicaciongroup
description: test description
nodeType: cache.t3.small
port: 6379
applyImmediately: true
autoMinorVersionUpgrade: false
maintenanceWindow: tue:06:30-tue:07:30
snapshotWindow: 01:00-02:00
logDeliveryConfigurations:
- destination: ${example.name}
destinationType: cloudwatch-logs
logFormat: text
logType: slow-log
- destination: ${exampleAwsKinesisFirehoseDeliveryStream.name}
destinationType: kinesis-firehose
logFormat: json
logType: engine-log
The logDeliveryConfigurations array defines where logs go. Each entry specifies a destination (log group or Firehose stream name), destinationType (cloudwatch-logs or kinesis-firehose), logFormat (text or json), and logType (slow-log or engine-log). Slow logs capture queries exceeding a threshold; engine logs capture Redis operational events.
Enable authentication and encryption in transit
Production deployments often require password authentication and encrypted connections to protect data in transit between clients and Redis nodes.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const example = new aws.elasticache.ReplicationGroup("example", {
replicationGroupId: "example",
description: "example with authentication",
nodeType: "cache.t2.micro",
numCacheClusters: 1,
port: 6379,
subnetGroupName: exampleAwsElasticacheSubnetGroup.name,
securityGroupIds: [exampleAwsSecurityGroup.id],
parameterGroupName: "default.redis5.0",
engineVersion: "5.0.6",
transitEncryptionEnabled: true,
authToken: "abcdefgh1234567890",
authTokenUpdateStrategy: "ROTATE",
});
import pulumi
import pulumi_aws as aws
example = aws.elasticache.ReplicationGroup("example",
replication_group_id="example",
description="example with authentication",
node_type="cache.t2.micro",
num_cache_clusters=1,
port=6379,
subnet_group_name=example_aws_elasticache_subnet_group["name"],
security_group_ids=[example_aws_security_group["id"]],
parameter_group_name="default.redis5.0",
engine_version="5.0.6",
transit_encryption_enabled=True,
auth_token="abcdefgh1234567890",
auth_token_update_strategy="ROTATE")
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/elasticache"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := elasticache.NewReplicationGroup(ctx, "example", &elasticache.ReplicationGroupArgs{
ReplicationGroupId: pulumi.String("example"),
Description: pulumi.String("example with authentication"),
NodeType: pulumi.String("cache.t2.micro"),
NumCacheClusters: pulumi.Int(1),
Port: pulumi.Int(6379),
SubnetGroupName: pulumi.Any(exampleAwsElasticacheSubnetGroup.Name),
SecurityGroupIds: pulumi.StringArray{
exampleAwsSecurityGroup.Id,
},
ParameterGroupName: pulumi.String("default.redis5.0"),
EngineVersion: pulumi.String("5.0.6"),
TransitEncryptionEnabled: pulumi.Bool(true),
AuthToken: pulumi.String("abcdefgh1234567890"),
AuthTokenUpdateStrategy: pulumi.String("ROTATE"),
})
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 example = new Aws.ElastiCache.ReplicationGroup("example", new()
{
ReplicationGroupId = "example",
Description = "example with authentication",
NodeType = "cache.t2.micro",
NumCacheClusters = 1,
Port = 6379,
SubnetGroupName = exampleAwsElasticacheSubnetGroup.Name,
SecurityGroupIds = new[]
{
exampleAwsSecurityGroup.Id,
},
ParameterGroupName = "default.redis5.0",
EngineVersion = "5.0.6",
TransitEncryptionEnabled = true,
AuthToken = "abcdefgh1234567890",
AuthTokenUpdateStrategy = "ROTATE",
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.elasticache.ReplicationGroup;
import com.pulumi.aws.elasticache.ReplicationGroupArgs;
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) {
var example = new ReplicationGroup("example", ReplicationGroupArgs.builder()
.replicationGroupId("example")
.description("example with authentication")
.nodeType("cache.t2.micro")
.numCacheClusters(1)
.port(6379)
.subnetGroupName(exampleAwsElasticacheSubnetGroup.name())
.securityGroupIds(exampleAwsSecurityGroup.id())
.parameterGroupName("default.redis5.0")
.engineVersion("5.0.6")
.transitEncryptionEnabled(true)
.authToken("abcdefgh1234567890")
.authTokenUpdateStrategy("ROTATE")
.build());
}
}
resources:
example:
type: aws:elasticache:ReplicationGroup
properties:
replicationGroupId: example
description: example with authentication
nodeType: cache.t2.micro
numCacheClusters: 1
port: 6379
subnetGroupName: ${exampleAwsElasticacheSubnetGroup.name}
securityGroupIds:
- ${exampleAwsSecurityGroup.id}
parameterGroupName: default.redis5.0
engineVersion: 5.0.6
transitEncryptionEnabled: true
authToken: abcdefgh1234567890
authTokenUpdateStrategy: ROTATE
The transitEncryptionEnabled property enables TLS encryption for client connections. The authToken property sets the password clients must provide. The authTokenUpdateStrategy controls how token changes are applied: ROTATE allows both old and new tokens temporarily, SET requires the new token immediately. Transit encryption requires a subnet group and security groups that allow encrypted traffic.
Beyond these examples
These snippets focus on specific replication group features: single-shard and multi-shard cluster topologies, availability zone placement and keyspace distribution, and log delivery and authentication. They’re intentionally minimal rather than full Redis deployments.
The examples may reference pre-existing infrastructure such as VPC subnet groups and security groups, CloudWatch log groups and Kinesis Firehose streams, and parameter groups with cluster mode enabled. They focus on configuring the replication group rather than provisioning everything around it.
To keep things focused, common replication group patterns are omitted, including:
- Encryption at rest (atRestEncryptionEnabled, kmsKeyId)
- Snapshot configuration (snapshotWindow, snapshotRetentionLimit)
- Global replication groups for multi-region deployments
- Maintenance windows and version upgrade controls
- Multi-AZ configuration (multiAzEnabled)
- User group associations for RBAC
These omissions are intentional: the goal is to illustrate how each replication group feature is wired, not provide drop-in Redis modules. See the ElastiCache Replication Group resource reference for all available configuration options.
Let's create AWS ElastiCache Replication Groups
Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.
Try Pulumi Cloud for FREEFrequently Asked Questions
Cluster Mode & Configuration
cluster-enabled set to true (e.g., default.redis6.x.cluster.on), then configure num_node_groups (number of shards) and replicas_per_node_group (0-5 replicas per shard).num_cache_clusters is for Cluster Mode Disabled (single shard with replicas, default 1). num_node_groups is for Cluster Mode Enabled (multiple shards). These parameters conflict with each other.Updates & Maintenance
apply_immediately = false), changes are applied during the next maintenance window. Setting it to true applies changes immediately but can cause brief downtime as servers reboot.apply_immediately value.7.2). Version 6: use major.minor (e.g., 6.2) or 6.x for latest. Version 5 and below: specify full version (e.g., 5.0.6).High Availability & Failover
num_cache_clusters must be at least 2. It’s required for cluster mode enabled replication groups.automatic_failover_enabled or multi_az_enabled is true, num_cache_clusters must be at least 2 (one primary and at least one replica).Security & Encryption
transit_encryption_enabled forces resource replacement and downtime. Version 7.0.5+ allows enabling it without replacement.transit_encryption_mode to preferred first (allows both encrypted and unencrypted connections), then set it to required in a subsequent apply after clients migrate.ROTATE allows both the new token and passwordless authentication (gradual migration). SET immediately requires the new token (no passwordless access). Use SET when adding the initial token for immediate authorization.redis engine, at_rest_encryption_enabled defaults to false. For valkey engine, it defaults to true. This property is immutable after creation.Scaling & Replicas
num_cache_clusters directly for automatic scaling, or (2) Use aws.elasticache.Cluster resources with replication_group_id for fine-grained control over AZ placement and cluster IDs (requires ignoreChanges on num_cache_clusters).Snapshots & Backups
snapshot_retention_limit is not supported on cache.t1.micro nodes. Use a different node type if you need snapshot retention.