Create AWS ElastiCache Clusters

The aws:elasticache/cluster:Cluster resource, part of the Pulumi AWS provider, provisions ElastiCache clusters: Memcached clusters for distributed caching, single-node Redis instances for data structures and persistence, or Redis read replicas in replication groups. This guide focuses on three capabilities: engine configuration, log delivery, and Outpost deployment.

ElastiCache clusters run in VPCs with security groups and subnets. Log delivery requires CloudWatch log groups or Kinesis Firehose streams. The examples are intentionally small. Combine them with your own VPC configuration, security groups, and monitoring infrastructure.

Create a Memcached cluster for distributed caching

Applications that cache session data or frequently accessed objects across multiple servers often use Memcached, which distributes data automatically across nodes.

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

const example = new aws.elasticache.Cluster("example", {
    clusterId: "cluster-example",
    engine: "memcached",
    nodeType: "cache.m4.large",
    numCacheNodes: 2,
    parameterGroupName: "default.memcached1.4",
    port: 11211,
});
import pulumi
import pulumi_aws as aws

example = aws.elasticache.Cluster("example",
    cluster_id="cluster-example",
    engine="memcached",
    node_type="cache.m4.large",
    num_cache_nodes=2,
    parameter_group_name="default.memcached1.4",
    port=11211)
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.NewCluster(ctx, "example", &elasticache.ClusterArgs{
			ClusterId:          pulumi.String("cluster-example"),
			Engine:             pulumi.String("memcached"),
			NodeType:           pulumi.String("cache.m4.large"),
			NumCacheNodes:      pulumi.Int(2),
			ParameterGroupName: pulumi.String("default.memcached1.4"),
			Port:               pulumi.Int(11211),
		})
		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.Cluster("example", new()
    {
        ClusterId = "cluster-example",
        Engine = "memcached",
        NodeType = "cache.m4.large",
        NumCacheNodes = 2,
        ParameterGroupName = "default.memcached1.4",
        Port = 11211,
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.elasticache.Cluster;
import com.pulumi.aws.elasticache.ClusterArgs;
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 Cluster("example", ClusterArgs.builder()
            .clusterId("cluster-example")
            .engine("memcached")
            .nodeType("cache.m4.large")
            .numCacheNodes(2)
            .parameterGroupName("default.memcached1.4")
            .port(11211)
            .build());

    }
}
resources:
  example:
    type: aws:elasticache:Cluster
    properties:
      clusterId: cluster-example
      engine: memcached
      nodeType: cache.m4.large
      numCacheNodes: 2
      parameterGroupName: default.memcached1.4
      port: 11211

When you create a Memcached cluster, data is distributed across all nodes automatically. The engine property selects Memcached, nodeType determines instance size, and numCacheNodes sets the node count (between 1 and 40). The parameterGroupName controls Memcached behavior like memory allocation and eviction policies.

Deploy a single-node Redis instance

Redis provides in-memory data structures with persistence, making it suitable for caching, session storage, and real-time analytics.

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

const example = new aws.elasticache.Cluster("example", {
    clusterId: "cluster-example",
    engine: "redis",
    nodeType: "cache.m4.large",
    numCacheNodes: 1,
    parameterGroupName: "default.redis3.2",
    engineVersion: "3.2.10",
    port: 6379,
});
import pulumi
import pulumi_aws as aws

example = aws.elasticache.Cluster("example",
    cluster_id="cluster-example",
    engine="redis",
    node_type="cache.m4.large",
    num_cache_nodes=1,
    parameter_group_name="default.redis3.2",
    engine_version="3.2.10",
    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.NewCluster(ctx, "example", &elasticache.ClusterArgs{
			ClusterId:          pulumi.String("cluster-example"),
			Engine:             pulumi.String("redis"),
			NodeType:           pulumi.String("cache.m4.large"),
			NumCacheNodes:      pulumi.Int(1),
			ParameterGroupName: pulumi.String("default.redis3.2"),
			EngineVersion:      pulumi.String("3.2.10"),
			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.Cluster("example", new()
    {
        ClusterId = "cluster-example",
        Engine = "redis",
        NodeType = "cache.m4.large",
        NumCacheNodes = 1,
        ParameterGroupName = "default.redis3.2",
        EngineVersion = "3.2.10",
        Port = 6379,
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.elasticache.Cluster;
import com.pulumi.aws.elasticache.ClusterArgs;
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 Cluster("example", ClusterArgs.builder()
            .clusterId("cluster-example")
            .engine("redis")
            .nodeType("cache.m4.large")
            .numCacheNodes(1)
            .parameterGroupName("default.redis3.2")
            .engineVersion("3.2.10")
            .port(6379)
            .build());

    }
}
resources:
  example:
    type: aws:elasticache:Cluster
    properties:
      clusterId: cluster-example
      engine: redis
      nodeType: cache.m4.large
      numCacheNodes: 1
      parameterGroupName: default.redis3.2
      engineVersion: 3.2.10
      port: 6379

For standalone Redis, numCacheNodes must be 1. The engineVersion property controls which Redis version runs; ElastiCache returns the actual version in engineVersionActual since it may apply minor patches automatically. Redis supports richer data types than Memcached, including lists, sets, and sorted sets.

Stream Redis logs to CloudWatch and Kinesis

Production Redis deployments capture slow queries and engine events for troubleshooting and performance analysis.

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

const test = new aws.elasticache.Cluster("test", {
    clusterId: "mycluster",
    engine: "redis",
    nodeType: "cache.t3.micro",
    numCacheNodes: 1,
    port: 6379,
    applyImmediately: true,
    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.Cluster("test",
    cluster_id="mycluster",
    engine="redis",
    node_type="cache.t3.micro",
    num_cache_nodes=1,
    port=6379,
    apply_immediately=True,
    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.NewCluster(ctx, "test", &elasticache.ClusterArgs{
			ClusterId:        pulumi.String("mycluster"),
			Engine:           pulumi.String("redis"),
			NodeType:         pulumi.String("cache.t3.micro"),
			NumCacheNodes:    pulumi.Int(1),
			Port:             pulumi.Int(6379),
			ApplyImmediately: pulumi.Bool(true),
			LogDeliveryConfigurations: elasticache.ClusterLogDeliveryConfigurationArray{
				&elasticache.ClusterLogDeliveryConfigurationArgs{
					Destination:     pulumi.Any(example.Name),
					DestinationType: pulumi.String("cloudwatch-logs"),
					LogFormat:       pulumi.String("text"),
					LogType:         pulumi.String("slow-log"),
				},
				&elasticache.ClusterLogDeliveryConfigurationArgs{
					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.Cluster("test", new()
    {
        ClusterId = "mycluster",
        Engine = "redis",
        NodeType = "cache.t3.micro",
        NumCacheNodes = 1,
        Port = 6379,
        ApplyImmediately = true,
        LogDeliveryConfigurations = new[]
        {
            new Aws.ElastiCache.Inputs.ClusterLogDeliveryConfigurationArgs
            {
                Destination = example.Name,
                DestinationType = "cloudwatch-logs",
                LogFormat = "text",
                LogType = "slow-log",
            },
            new Aws.ElastiCache.Inputs.ClusterLogDeliveryConfigurationArgs
            {
                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.Cluster;
import com.pulumi.aws.elasticache.ClusterArgs;
import com.pulumi.aws.elasticache.inputs.ClusterLogDeliveryConfigurationArgs;
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 Cluster("test", ClusterArgs.builder()
            .clusterId("mycluster")
            .engine("redis")
            .nodeType("cache.t3.micro")
            .numCacheNodes(1)
            .port(6379)
            .applyImmediately(true)
            .logDeliveryConfigurations(            
                ClusterLogDeliveryConfigurationArgs.builder()
                    .destination(example.name())
                    .destinationType("cloudwatch-logs")
                    .logFormat("text")
                    .logType("slow-log")
                    .build(),
                ClusterLogDeliveryConfigurationArgs.builder()
                    .destination(exampleAwsKinesisFirehoseDeliveryStream.name())
                    .destinationType("kinesis-firehose")
                    .logFormat("json")
                    .logType("engine-log")
                    .build())
            .build());

    }
}
resources:
  test:
    type: aws:elasticache:Cluster
    properties:
      clusterId: mycluster
      engine: redis
      nodeType: cache.t3.micro
      numCacheNodes: 1
      port: 6379
      applyImmediately: true
      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 how they’re formatted. Each configuration specifies a destinationType (CloudWatch Logs or Kinesis Firehose), a destination name, a logType (slow-log or engine-log), and a logFormat (text or json). Slow logs capture queries exceeding execution time thresholds; engine logs record Redis operational events.

Deploy ElastiCache on AWS Outposts

Applications on AWS Outposts can run ElastiCache locally to minimize latency and keep data on-premises.

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

const example = aws.outposts.getOutposts({});
const exampleGetOutpost = example.then(example => aws.outposts.getOutpost({
    id: example.ids?.[0],
}));
const exampleVpc = new aws.ec2.Vpc("example", {cidrBlock: "10.0.0.0/16"});
const exampleSubnet = new aws.ec2.Subnet("example", {
    vpcId: exampleVpc.id,
    cidrBlock: "10.0.1.0/24",
    tags: {
        Name: "my-subnet",
    },
});
const exampleSubnetGroup = new aws.elasticache.SubnetGroup("example", {
    name: "my-cache-subnet",
    subnetIds: [exampleSubnet.id],
});
const exampleCluster = new aws.elasticache.Cluster("example", {
    clusterId: "cluster-example",
    outpostMode: "single-outpost",
    preferredOutpostArn: exampleGetOutpost.then(exampleGetOutpost => exampleGetOutpost.arn),
    engine: "memcached",
    nodeType: "cache.r5.large",
    numCacheNodes: 2,
    parameterGroupName: "default.memcached1.4",
    port: 11211,
    subnetGroupName: exampleSubnetGroup.name,
});
import pulumi
import pulumi_aws as aws

example = aws.outposts.get_outposts()
example_get_outpost = aws.outposts.get_outpost(id=example.ids[0])
example_vpc = aws.ec2.Vpc("example", cidr_block="10.0.0.0/16")
example_subnet = aws.ec2.Subnet("example",
    vpc_id=example_vpc.id,
    cidr_block="10.0.1.0/24",
    tags={
        "Name": "my-subnet",
    })
example_subnet_group = aws.elasticache.SubnetGroup("example",
    name="my-cache-subnet",
    subnet_ids=[example_subnet.id])
example_cluster = aws.elasticache.Cluster("example",
    cluster_id="cluster-example",
    outpost_mode="single-outpost",
    preferred_outpost_arn=example_get_outpost.arn,
    engine="memcached",
    node_type="cache.r5.large",
    num_cache_nodes=2,
    parameter_group_name="default.memcached1.4",
    port=11211,
    subnet_group_name=example_subnet_group.name)
package main

import (
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/ec2"
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/elasticache"
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/outposts"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		example, err := outposts.GetOutposts(ctx, &outposts.GetOutpostsArgs{}, nil)
		if err != nil {
			return err
		}
		exampleGetOutpost, err := outposts.GetOutpost(ctx, &outposts.GetOutpostArgs{
			Id: pulumi.StringRef(example.Ids[0]),
		}, nil)
		if err != nil {
			return err
		}
		exampleVpc, err := ec2.NewVpc(ctx, "example", &ec2.VpcArgs{
			CidrBlock: pulumi.String("10.0.0.0/16"),
		})
		if err != nil {
			return err
		}
		exampleSubnet, err := ec2.NewSubnet(ctx, "example", &ec2.SubnetArgs{
			VpcId:     exampleVpc.ID(),
			CidrBlock: pulumi.String("10.0.1.0/24"),
			Tags: pulumi.StringMap{
				"Name": pulumi.String("my-subnet"),
			},
		})
		if err != nil {
			return err
		}
		exampleSubnetGroup, err := elasticache.NewSubnetGroup(ctx, "example", &elasticache.SubnetGroupArgs{
			Name: pulumi.String("my-cache-subnet"),
			SubnetIds: pulumi.StringArray{
				exampleSubnet.ID(),
			},
		})
		if err != nil {
			return err
		}
		_, err = elasticache.NewCluster(ctx, "example", &elasticache.ClusterArgs{
			ClusterId:           pulumi.String("cluster-example"),
			OutpostMode:         pulumi.String("single-outpost"),
			PreferredOutpostArn: pulumi.String(exampleGetOutpost.Arn),
			Engine:              pulumi.String("memcached"),
			NodeType:            pulumi.String("cache.r5.large"),
			NumCacheNodes:       pulumi.Int(2),
			ParameterGroupName:  pulumi.String("default.memcached1.4"),
			Port:                pulumi.Int(11211),
			SubnetGroupName:     exampleSubnetGroup.Name,
		})
		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 = Aws.Outposts.GetOutposts.Invoke();

    var exampleGetOutpost = Aws.Outposts.GetOutpost.Invoke(new()
    {
        Id = example.Apply(getOutpostsResult => getOutpostsResult.Ids[0]),
    });

    var exampleVpc = new Aws.Ec2.Vpc("example", new()
    {
        CidrBlock = "10.0.0.0/16",
    });

    var exampleSubnet = new Aws.Ec2.Subnet("example", new()
    {
        VpcId = exampleVpc.Id,
        CidrBlock = "10.0.1.0/24",
        Tags = 
        {
            { "Name", "my-subnet" },
        },
    });

    var exampleSubnetGroup = new Aws.ElastiCache.SubnetGroup("example", new()
    {
        Name = "my-cache-subnet",
        SubnetIds = new[]
        {
            exampleSubnet.Id,
        },
    });

    var exampleCluster = new Aws.ElastiCache.Cluster("example", new()
    {
        ClusterId = "cluster-example",
        OutpostMode = "single-outpost",
        PreferredOutpostArn = exampleGetOutpost.Apply(getOutpostResult => getOutpostResult.Arn),
        Engine = "memcached",
        NodeType = "cache.r5.large",
        NumCacheNodes = 2,
        ParameterGroupName = "default.memcached1.4",
        Port = 11211,
        SubnetGroupName = exampleSubnetGroup.Name,
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.outposts.OutpostsFunctions;
import com.pulumi.aws.outposts.inputs.GetOutpostsArgs;
import com.pulumi.aws.outposts.inputs.GetOutpostArgs;
import com.pulumi.aws.ec2.Vpc;
import com.pulumi.aws.ec2.VpcArgs;
import com.pulumi.aws.ec2.Subnet;
import com.pulumi.aws.ec2.SubnetArgs;
import com.pulumi.aws.elasticache.SubnetGroup;
import com.pulumi.aws.elasticache.SubnetGroupArgs;
import com.pulumi.aws.elasticache.Cluster;
import com.pulumi.aws.elasticache.ClusterArgs;
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 example = OutpostsFunctions.getOutposts(GetOutpostsArgs.builder()
            .build());

        final var exampleGetOutpost = OutpostsFunctions.getOutpost(GetOutpostArgs.builder()
            .id(example.ids()[0])
            .build());

        var exampleVpc = new Vpc("exampleVpc", VpcArgs.builder()
            .cidrBlock("10.0.0.0/16")
            .build());

        var exampleSubnet = new Subnet("exampleSubnet", SubnetArgs.builder()
            .vpcId(exampleVpc.id())
            .cidrBlock("10.0.1.0/24")
            .tags(Map.of("Name", "my-subnet"))
            .build());

        var exampleSubnetGroup = new SubnetGroup("exampleSubnetGroup", SubnetGroupArgs.builder()
            .name("my-cache-subnet")
            .subnetIds(exampleSubnet.id())
            .build());

        var exampleCluster = new Cluster("exampleCluster", ClusterArgs.builder()
            .clusterId("cluster-example")
            .outpostMode("single-outpost")
            .preferredOutpostArn(exampleGetOutpost.arn())
            .engine("memcached")
            .nodeType("cache.r5.large")
            .numCacheNodes(2)
            .parameterGroupName("default.memcached1.4")
            .port(11211)
            .subnetGroupName(exampleSubnetGroup.name())
            .build());

    }
}
resources:
  exampleVpc:
    type: aws:ec2:Vpc
    name: example
    properties:
      cidrBlock: 10.0.0.0/16
  exampleSubnet:
    type: aws:ec2:Subnet
    name: example
    properties:
      vpcId: ${exampleVpc.id}
      cidrBlock: 10.0.1.0/24
      tags:
        Name: my-subnet
  exampleSubnetGroup:
    type: aws:elasticache:SubnetGroup
    name: example
    properties:
      name: my-cache-subnet
      subnetIds:
        - ${exampleSubnet.id}
  exampleCluster:
    type: aws:elasticache:Cluster
    name: example
    properties:
      clusterId: cluster-example
      outpostMode: single-outpost
      preferredOutpostArn: ${exampleGetOutpost.arn}
      engine: memcached
      nodeType: cache.r5.large
      numCacheNodes: 2
      parameterGroupName: default.memcached1.4
      port: 11211
      subnetGroupName: ${exampleSubnetGroup.name}
variables:
  example:
    fn::invoke:
      function: aws:outposts:getOutposts
      arguments: {}
  exampleGetOutpost:
    fn::invoke:
      function: aws:outposts:getOutpost
      arguments:
        id: ${example.ids[0]}

The outpostMode property must be “single-outpost” (AWS currently supports only this mode). The preferredOutpostArn identifies which Outpost hosts the cluster. You must also specify a subnetGroupName that references subnets configured for the Outpost.

Beyond these examples

These snippets focus on specific cluster-level features: Memcached and Redis engine configuration, log delivery to CloudWatch and Kinesis, and Outpost deployment. They’re intentionally minimal rather than full caching solutions.

The examples may reference pre-existing infrastructure such as VPC, subnets, and security groups (most use defaults), CloudWatch log groups and Kinesis Firehose streams for log delivery, and AWS Outposts infrastructure for Outpost deployment. They focus on configuring the cluster rather than provisioning everything around it.

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

  • VPC networking and security group configuration
  • Multi-AZ placement (azMode, preferredAvailabilityZones)
  • Snapshot and backup configuration (snapshotRetentionLimit, snapshotWindow)
  • Encryption in transit (transitEncryptionEnabled)
  • Replication group integration for Redis clustering
  • Maintenance windows and immediate application (applyImmediately)

These omissions are intentional: the goal is to illustrate how each cluster feature is wired, not provide drop-in caching modules. See the ElastiCache Cluster resource reference for all available configuration options.

Let's create AWS ElastiCache Clusters

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

Try Pulumi Cloud for FREE

Frequently Asked Questions

Configuration & Updates
Why aren't my configuration changes applying immediately?
By default, changes like num_cache_nodes apply during the next maintenance window. Set apply_immediately to true to apply changes immediately, though this can cause brief downtime due to server reboots.
What's the difference between apply_immediately and properties that force re-creation?
Changes that re-create the resource (like modifying cluster_id, engine, or port) apply immediately regardless of the apply_immediately setting. Only in-place updates respect the maintenance window.
What properties can't be changed after creation?
These properties are immutable and force re-creation: cluster_id, engine, availability_zone, port, replication_group_id, subnet_group_name, transit_encryption_enabled, network_type, preferred_outpost_arn, outpost_mode, snapshot_arns, and snapshot_name. For Memcached, node_type is also immutable.
Engine & Versioning
What cache engines are supported?
ElastiCache Cluster supports three engines: memcached, redis, and valkey. The engine choice is immutable after creation.
How do I specify the Redis engine version?
For Redis 7+, use major.minor format (e.g., 7.2). For Redis 6, you can specify 6.2 or use 6.x for the latest 6.x version. For earlier versions, specify the full version (e.g., 5.0.6). The actual version used is returned in engine_version_actual.
Will my cluster automatically upgrade to new minor versions?
For Redis engine version 6 or higher, auto_minor_version_upgrade defaults to true, applying minor version upgrades during maintenance windows. This setting only applies to Redis.
Scaling & High Availability
How many cache nodes can I have?
Redis clusters must have exactly 1 node. Memcached clusters can have 1 to 40 nodes. When reducing num_cache_nodes, the highest numbered nodes are removed.
How do I configure multi-AZ deployment?
For a single AZ, use availability_zone. For multiple AZs, use preferred_availability_zones (list must match num_cache_nodes count). For Memcached, set az_mode to cross-az (requires num_cache_nodes > 1).
Why does updating preferred_availability_zones show a perpetual difference?
Drift detection for existing node availability zones isn’t supported. Updating preferred_availability_zones to migrate existing nodes will show a perpetual difference. Use this property only during initial creation.
How do I create a read replica?
Set replication_group_id to the ID of an existing replication group. The cluster becomes a read replica and inherits settings from the replication group.
Networking & Security
What are the default connection ports?
Memcached defaults to port 11211, and Redis defaults to port 6379. The port is immutable after creation.
When can I enable transit encryption?
Transit encryption is supported with Memcached versions 1.6.12+, Valkey 7.2+, and Redis versions 3.2.6, 4.0.10 and later, running in a VPC. This setting is immutable.
When is IPv6 supported?
IPv6 is supported with Redis engine 6.2 onward or Memcached version 1.6.6 on Nitro system instances. Set network_type to ipv6 or dual_stack.
Snapshots & Backups
Can I enable snapshot retention on all node types?
No, setting snapshot_retention_limit isn’t supported on cache.t1.micro nodes. Use a different node type if snapshot retention is required.

Using a different cloud?

Explore database guides for other cloud providers: