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, optional sharding, and high availability features. This guide focuses on three capabilities: single-shard and multi-shard cluster configurations, encryption and authentication, and log delivery to CloudWatch and Kinesis.
Replication groups run in VPC subnet groups with security groups, and may reference parameter groups, CloudWatch log groups, or Kinesis streams. The examples are intentionally small. Combine them with your own VPC infrastructure, parameter groups, and monitoring destinations.
Create a single-shard cluster with automatic failover
Most Redis deployments begin with a simple replication group: one primary node and one or more read replicas for high availability.
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 automaticFailoverEnabled is true, ElastiCache promotes a replica to primary if the current primary fails. The numCacheClusters property sets the total count (primary plus replicas); with automatic failover enabled, you need at least 2. The preferredCacheClusterAzs list controls placement, with the first zone hosting the primary. The parameterGroupName determines Redis configuration; use a parameter group with cluster-enabled set to false for single-shard mode.
Enable cluster mode for horizontal scaling
Applications that need to scale beyond a single shard use cluster mode, which distributes data across multiple node groups.
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
Cluster mode shards data using hash slots. The numNodeGroups property sets the number of shards, and replicasPerNodeGroup controls how many replicas each shard has. The parameterGroupName must reference a parameter group with cluster-enabled set to true (AWS provides defaults like default.redis3.2.cluster.on). Automatic failover is required for cluster mode.
Control shard placement and keyspace distribution
For precise control over availability zone placement and hash slot distribution, you can configure each node group individually.
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 specify exactly where each shard runs and which hash slots it owns. Each configuration sets a nodeGroupId, the primaryAvailabilityZone, replicaAvailabilityZones for replicas, and the slots range (Redis uses 16,384 hash slots total). This gives you control over data locality and failure domain isolation.
Stream logs to CloudWatch and Kinesis Firehose
Production clusters often need to capture slow queries and engine logs for debugging and performance analysis.
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 and in what format. Each configuration specifies a logType (slow-log or engine-log), a destinationType (cloudwatch-logs or kinesis-firehose), the destination name, and a logFormat (text or json). Slow logs capture queries that exceed a threshold; engine logs record Redis operational events.
Secure connections with encryption and authentication
Sensitive workloads require encryption in transit and password authentication to prevent unauthorized access.
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
When transitEncryptionEnabled is true, all client connections use TLS. The authToken property sets a password for Redis AUTH; it only works when transit encryption is enabled. The authTokenUpdateStrategy controls how token changes are applied: SET requires the new token immediately, ROTATE allows both old and new tokens temporarily, and DELETE removes authentication. The subnetGroupName and securityGroupIds place the cluster in your VPC with network-level access control.
Beyond these examples
These snippets focus on specific replication group features: cluster mode and sharding configuration, encryption and authentication, and log delivery and monitoring. 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:
- Global replication groups for multi-region deployments
- Snapshot and backup configuration (snapshotRetentionLimit, snapshotWindow)
- Maintenance windows and version upgrade controls
- Multi-AZ configuration (multiAzEnabled)
- Data tiering for r6gd node types
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 ReplicationGroup 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, such as default.redis6.x.cluster.on.num_cache_clusters for Cluster Mode Disabled (single shard with replicas). Use num_node_groups and replicas_per_node_group for Cluster Mode Enabled (multiple shards). These parameters conflict with each other and cannot be used together.num_cache_clusters directly for automatic scaling, or (2) Use aws.elasticache.Cluster resources with replication_group_id for fine-grained control over availability zones and cluster IDs. Option 2 requires using ignoreChanges on num_cache_clusters.Updates & Maintenance
engine_version are applied during the next maintenance window. Set apply_immediately to true to apply changes immediately, but this can cause brief downtime due to server reboots. Note that any changes forcing resource re-creation are always applied immediately, regardless of apply_immediately.7.2). For version 6, you can set major.minor (e.g., 6.2) or use 6.x to get the latest minor version at creation time. For earlier versions, specify the full version (e.g., 5.0.6). The actual version used is returned in engine_version_actual.auto_minor_version_upgrade parameter defaults to true for Redis and Valkey engines with version 6 or higher. Minor version upgrades are applied during the maintenance window.High Availability & Failover
num_cache_clusters must be at least 2. For T2 node types, you need Redis 3.2.4 or later with cluster mode enabled. Automatic failover is required for cluster mode enabled replication groups.multi_az_enabled is true, then automatic_failover_enabled must also be true, and num_cache_clusters must be at least 2. Both default to false.Security & Encryption
auth_token to a previously passwordless replication group, ROTATE allows both the new token and passwordless authentication. To immediately require authorization, use SET instead. If omitted, AWS defaults to ROTATE.transit_encryption_mode to preferred, then in a subsequent apply set it to required. Note that changing transit_encryption_enabled with engine_version less than 7.0.5 will force resource replacement.at_rest_encryption_enabled: Redis defaults to false, while Valkey defaults to true. This property is immutable after creation.Scaling & Replicas
replicas_per_node_group to configure this (only valid when num_node_groups is set).global_replication_group_id is set, you cannot set num_node_groups. The global replication group controls the number of node groups.Snapshots & Special Node Types
snapshot_retention_limit is not supported on cache.t1.micro nodes. You’ll need to use a different node type to enable automatic snapshots.data_tiering_enabled to true. Data tiering is only supported for r6gd node types, and this property is immutable after creation.