Create AWS ElastiCache Serverless Caches

The aws:elasticache/serverlessCache:ServerlessCache resource, part of the Pulumi AWS provider, provisions ElastiCache Serverless caches that automatically scale capacity based on workload demand. This guide focuses on three capabilities: engine selection (Memcached, Redis, Valkey), usage limits for storage and compute, and snapshot configuration for Redis and Valkey.

Serverless caches run in VPC subnets with security groups and optionally use KMS keys for encryption. The examples are intentionally small. Combine them with your own VPC infrastructure, security groups, and encryption keys.

Deploy a Memcached serverless cache with usage limits

Teams building caching layers often start with Memcached for simple key-value storage without persistence requirements.

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

const example = new aws.elasticache.ServerlessCache("example", {
    engine: "memcached",
    name: "example",
    cacheUsageLimits: {
        dataStorage: {
            maximum: 10,
            unit: "GB",
        },
        ecpuPerSeconds: [{
            maximum: 5000,
        }],
    },
    description: "Test Server",
    kmsKeyId: test.arn,
    majorEngineVersion: "1.6",
    securityGroupIds: [testAwsSecurityGroup.id],
    subnetIds: testAwsSubnet.map(__item => __item.id),
});
import pulumi
import pulumi_aws as aws

example = aws.elasticache.ServerlessCache("example",
    engine="memcached",
    name="example",
    cache_usage_limits={
        "data_storage": {
            "maximum": 10,
            "unit": "GB",
        },
        "ecpu_per_seconds": [{
            "maximum": 5000,
        }],
    },
    description="Test Server",
    kms_key_id=test["arn"],
    major_engine_version="1.6",
    security_group_ids=[test_aws_security_group["id"]],
    subnet_ids=[__item["id"] for __item in test_aws_subnet])
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 {
var splat0 []interface{}
for _, val0 := range testAwsSubnet {
splat0 = append(splat0, val0.Id)
}
_, err := elasticache.NewServerlessCache(ctx, "example", &elasticache.ServerlessCacheArgs{
Engine: pulumi.String("memcached"),
Name: pulumi.String("example"),
CacheUsageLimits: &elasticache.ServerlessCacheCacheUsageLimitsArgs{
DataStorage: &elasticache.ServerlessCacheCacheUsageLimitsDataStorageArgs{
Maximum: pulumi.Int(10),
Unit: pulumi.String("GB"),
},
EcpuPerSeconds: elasticache.ServerlessCacheCacheUsageLimitsEcpuPerSecondArray{
&elasticache.ServerlessCacheCacheUsageLimitsEcpuPerSecondArgs{
Maximum: pulumi.Int(5000),
},
},
},
Description: pulumi.String("Test Server"),
KmsKeyId: pulumi.Any(test.Arn),
MajorEngineVersion: pulumi.String("1.6"),
SecurityGroupIds: pulumi.StringArray{
testAwsSecurityGroup.Id,
},
SubnetIds: toPulumiArray(splat0),
})
if err != nil {
return err
}
return nil
})
}
func toPulumiArray(arr []) pulumi.Array {
var pulumiArr pulumi.Array
for _, v := range arr {
pulumiArr = append(pulumiArr, pulumi.(v))
}
return pulumiArr
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;

return await Deployment.RunAsync(() => 
{
    var example = new Aws.ElastiCache.ServerlessCache("example", new()
    {
        Engine = "memcached",
        Name = "example",
        CacheUsageLimits = new Aws.ElastiCache.Inputs.ServerlessCacheCacheUsageLimitsArgs
        {
            DataStorage = new Aws.ElastiCache.Inputs.ServerlessCacheCacheUsageLimitsDataStorageArgs
            {
                Maximum = 10,
                Unit = "GB",
            },
            EcpuPerSeconds = new[]
            {
                new Aws.ElastiCache.Inputs.ServerlessCacheCacheUsageLimitsEcpuPerSecondArgs
                {
                    Maximum = 5000,
                },
            },
        },
        Description = "Test Server",
        KmsKeyId = test.Arn,
        MajorEngineVersion = "1.6",
        SecurityGroupIds = new[]
        {
            testAwsSecurityGroup.Id,
        },
        SubnetIds = testAwsSubnet.Select(__item => __item.Id).ToList(),
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.elasticache.ServerlessCache;
import com.pulumi.aws.elasticache.ServerlessCacheArgs;
import com.pulumi.aws.elasticache.inputs.ServerlessCacheCacheUsageLimitsArgs;
import com.pulumi.aws.elasticache.inputs.ServerlessCacheCacheUsageLimitsDataStorageArgs;
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 ServerlessCache("example", ServerlessCacheArgs.builder()
            .engine("memcached")
            .name("example")
            .cacheUsageLimits(ServerlessCacheCacheUsageLimitsArgs.builder()
                .dataStorage(ServerlessCacheCacheUsageLimitsDataStorageArgs.builder()
                    .maximum(10)
                    .unit("GB")
                    .build())
                .ecpuPerSeconds(ServerlessCacheCacheUsageLimitsEcpuPerSecondArgs.builder()
                    .maximum(5000)
                    .build())
                .build())
            .description("Test Server")
            .kmsKeyId(test.arn())
            .majorEngineVersion("1.6")
            .securityGroupIds(testAwsSecurityGroup.id())
            .subnetIds(testAwsSubnet.stream().map(element -> element.id()).collect(toList()))
            .build());

    }
}

The cacheUsageLimits property caps both storage (dataStorage.maximum in GB) and compute (ecpuPerSeconds.maximum for ElastiCache Processing Units). ElastiCache automatically scales within these limits based on workload demand. Memcached doesn’t support snapshots, so dailySnapshotTime and snapshotRetentionLimit are omitted.

Deploy Redis with daily snapshots and retention

Applications requiring data persistence use Redis with snapshot backups to recover from failures or restore to previous states.

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

const example = new aws.elasticache.ServerlessCache("example", {
    engine: "redis",
    name: "example",
    cacheUsageLimits: {
        dataStorage: {
            maximum: 10,
            unit: "GB",
        },
        ecpuPerSeconds: [{
            maximum: 5000,
        }],
    },
    dailySnapshotTime: "09:00",
    description: "Test Server",
    kmsKeyId: test.arn,
    majorEngineVersion: "7",
    snapshotRetentionLimit: 1,
    securityGroupIds: [testAwsSecurityGroup.id],
    subnetIds: testAwsSubnet.map(__item => __item.id),
});
import pulumi
import pulumi_aws as aws

example = aws.elasticache.ServerlessCache("example",
    engine="redis",
    name="example",
    cache_usage_limits={
        "data_storage": {
            "maximum": 10,
            "unit": "GB",
        },
        "ecpu_per_seconds": [{
            "maximum": 5000,
        }],
    },
    daily_snapshot_time="09:00",
    description="Test Server",
    kms_key_id=test["arn"],
    major_engine_version="7",
    snapshot_retention_limit=1,
    security_group_ids=[test_aws_security_group["id"]],
    subnet_ids=[__item["id"] for __item in test_aws_subnet])
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 {
var splat0 []interface{}
for _, val0 := range testAwsSubnet {
splat0 = append(splat0, val0.Id)
}
_, err := elasticache.NewServerlessCache(ctx, "example", &elasticache.ServerlessCacheArgs{
Engine: pulumi.String("redis"),
Name: pulumi.String("example"),
CacheUsageLimits: &elasticache.ServerlessCacheCacheUsageLimitsArgs{
DataStorage: &elasticache.ServerlessCacheCacheUsageLimitsDataStorageArgs{
Maximum: pulumi.Int(10),
Unit: pulumi.String("GB"),
},
EcpuPerSeconds: elasticache.ServerlessCacheCacheUsageLimitsEcpuPerSecondArray{
&elasticache.ServerlessCacheCacheUsageLimitsEcpuPerSecondArgs{
Maximum: pulumi.Int(5000),
},
},
},
DailySnapshotTime: pulumi.String("09:00"),
Description: pulumi.String("Test Server"),
KmsKeyId: pulumi.Any(test.Arn),
MajorEngineVersion: pulumi.String("7"),
SnapshotRetentionLimit: pulumi.Int(1),
SecurityGroupIds: pulumi.StringArray{
testAwsSecurityGroup.Id,
},
SubnetIds: toPulumiArray(splat0),
})
if err != nil {
return err
}
return nil
})
}
func toPulumiArray(arr []) pulumi.Array {
var pulumiArr pulumi.Array
for _, v := range arr {
pulumiArr = append(pulumiArr, pulumi.(v))
}
return pulumiArr
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;

return await Deployment.RunAsync(() => 
{
    var example = new Aws.ElastiCache.ServerlessCache("example", new()
    {
        Engine = "redis",
        Name = "example",
        CacheUsageLimits = new Aws.ElastiCache.Inputs.ServerlessCacheCacheUsageLimitsArgs
        {
            DataStorage = new Aws.ElastiCache.Inputs.ServerlessCacheCacheUsageLimitsDataStorageArgs
            {
                Maximum = 10,
                Unit = "GB",
            },
            EcpuPerSeconds = new[]
            {
                new Aws.ElastiCache.Inputs.ServerlessCacheCacheUsageLimitsEcpuPerSecondArgs
                {
                    Maximum = 5000,
                },
            },
        },
        DailySnapshotTime = "09:00",
        Description = "Test Server",
        KmsKeyId = test.Arn,
        MajorEngineVersion = "7",
        SnapshotRetentionLimit = 1,
        SecurityGroupIds = new[]
        {
            testAwsSecurityGroup.Id,
        },
        SubnetIds = testAwsSubnet.Select(__item => __item.Id).ToList(),
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.elasticache.ServerlessCache;
import com.pulumi.aws.elasticache.ServerlessCacheArgs;
import com.pulumi.aws.elasticache.inputs.ServerlessCacheCacheUsageLimitsArgs;
import com.pulumi.aws.elasticache.inputs.ServerlessCacheCacheUsageLimitsDataStorageArgs;
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 ServerlessCache("example", ServerlessCacheArgs.builder()
            .engine("redis")
            .name("example")
            .cacheUsageLimits(ServerlessCacheCacheUsageLimitsArgs.builder()
                .dataStorage(ServerlessCacheCacheUsageLimitsDataStorageArgs.builder()
                    .maximum(10)
                    .unit("GB")
                    .build())
                .ecpuPerSeconds(ServerlessCacheCacheUsageLimitsEcpuPerSecondArgs.builder()
                    .maximum(5000)
                    .build())
                .build())
            .dailySnapshotTime("09:00")
            .description("Test Server")
            .kmsKeyId(test.arn())
            .majorEngineVersion("7")
            .snapshotRetentionLimit(1)
            .securityGroupIds(testAwsSecurityGroup.id())
            .subnetIds(testAwsSubnet.stream().map(element -> element.id()).collect(toList()))
            .build());

    }
}

Redis adds persistence through daily snapshots. The dailySnapshotTime property sets when snapshots are created (format: “HH:MM”), and snapshotRetentionLimit controls how many snapshots to retain before deleting the oldest. The cacheUsageLimits work identically to Memcached, capping storage and compute.

Deploy Valkey with snapshot configuration

Valkey provides Redis-compatible caching with the same persistence and snapshot capabilities for teams seeking an open-source alternative.

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

const example = new aws.elasticache.ServerlessCache("example", {
    engine: "valkey",
    name: "example",
    cacheUsageLimits: {
        dataStorage: {
            maximum: 10,
            unit: "GB",
        },
        ecpuPerSeconds: [{
            maximum: 5000,
        }],
    },
    dailySnapshotTime: "09:00",
    description: "Test Server",
    kmsKeyId: test.arn,
    majorEngineVersion: "7",
    snapshotRetentionLimit: 1,
    securityGroupIds: [testAwsSecurityGroup.id],
    subnetIds: testAwsSubnet.map(__item => __item.id),
});
import pulumi
import pulumi_aws as aws

example = aws.elasticache.ServerlessCache("example",
    engine="valkey",
    name="example",
    cache_usage_limits={
        "data_storage": {
            "maximum": 10,
            "unit": "GB",
        },
        "ecpu_per_seconds": [{
            "maximum": 5000,
        }],
    },
    daily_snapshot_time="09:00",
    description="Test Server",
    kms_key_id=test["arn"],
    major_engine_version="7",
    snapshot_retention_limit=1,
    security_group_ids=[test_aws_security_group["id"]],
    subnet_ids=[__item["id"] for __item in test_aws_subnet])
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 {
var splat0 []interface{}
for _, val0 := range testAwsSubnet {
splat0 = append(splat0, val0.Id)
}
_, err := elasticache.NewServerlessCache(ctx, "example", &elasticache.ServerlessCacheArgs{
Engine: pulumi.String("valkey"),
Name: pulumi.String("example"),
CacheUsageLimits: &elasticache.ServerlessCacheCacheUsageLimitsArgs{
DataStorage: &elasticache.ServerlessCacheCacheUsageLimitsDataStorageArgs{
Maximum: pulumi.Int(10),
Unit: pulumi.String("GB"),
},
EcpuPerSeconds: elasticache.ServerlessCacheCacheUsageLimitsEcpuPerSecondArray{
&elasticache.ServerlessCacheCacheUsageLimitsEcpuPerSecondArgs{
Maximum: pulumi.Int(5000),
},
},
},
DailySnapshotTime: pulumi.String("09:00"),
Description: pulumi.String("Test Server"),
KmsKeyId: pulumi.Any(test.Arn),
MajorEngineVersion: pulumi.String("7"),
SnapshotRetentionLimit: pulumi.Int(1),
SecurityGroupIds: pulumi.StringArray{
testAwsSecurityGroup.Id,
},
SubnetIds: toPulumiArray(splat0),
})
if err != nil {
return err
}
return nil
})
}
func toPulumiArray(arr []) pulumi.Array {
var pulumiArr pulumi.Array
for _, v := range arr {
pulumiArr = append(pulumiArr, pulumi.(v))
}
return pulumiArr
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;

return await Deployment.RunAsync(() => 
{
    var example = new Aws.ElastiCache.ServerlessCache("example", new()
    {
        Engine = "valkey",
        Name = "example",
        CacheUsageLimits = new Aws.ElastiCache.Inputs.ServerlessCacheCacheUsageLimitsArgs
        {
            DataStorage = new Aws.ElastiCache.Inputs.ServerlessCacheCacheUsageLimitsDataStorageArgs
            {
                Maximum = 10,
                Unit = "GB",
            },
            EcpuPerSeconds = new[]
            {
                new Aws.ElastiCache.Inputs.ServerlessCacheCacheUsageLimitsEcpuPerSecondArgs
                {
                    Maximum = 5000,
                },
            },
        },
        DailySnapshotTime = "09:00",
        Description = "Test Server",
        KmsKeyId = test.Arn,
        MajorEngineVersion = "7",
        SnapshotRetentionLimit = 1,
        SecurityGroupIds = new[]
        {
            testAwsSecurityGroup.Id,
        },
        SubnetIds = testAwsSubnet.Select(__item => __item.Id).ToList(),
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.elasticache.ServerlessCache;
import com.pulumi.aws.elasticache.ServerlessCacheArgs;
import com.pulumi.aws.elasticache.inputs.ServerlessCacheCacheUsageLimitsArgs;
import com.pulumi.aws.elasticache.inputs.ServerlessCacheCacheUsageLimitsDataStorageArgs;
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 ServerlessCache("example", ServerlessCacheArgs.builder()
            .engine("valkey")
            .name("example")
            .cacheUsageLimits(ServerlessCacheCacheUsageLimitsArgs.builder()
                .dataStorage(ServerlessCacheCacheUsageLimitsDataStorageArgs.builder()
                    .maximum(10)
                    .unit("GB")
                    .build())
                .ecpuPerSeconds(ServerlessCacheCacheUsageLimitsEcpuPerSecondArgs.builder()
                    .maximum(5000)
                    .build())
                .build())
            .dailySnapshotTime("09:00")
            .description("Test Server")
            .kmsKeyId(test.arn())
            .majorEngineVersion("7")
            .snapshotRetentionLimit(1)
            .securityGroupIds(testAwsSecurityGroup.id())
            .subnetIds(testAwsSubnet.stream().map(element -> element.id()).collect(toList()))
            .build());

    }
}

Valkey uses identical snapshot configuration to Redis: dailySnapshotTime and snapshotRetentionLimit control backup timing and retention. The majorEngineVersion property specifies the Valkey version (7 in this example), which determines available features and compatibility.

Beyond these examples

These snippets focus on specific serverless cache features: engine selection (Memcached, Redis, Valkey), usage limits and automatic scaling, and snapshot configuration for persistence. They’re intentionally minimal rather than full caching deployments.

The examples reference pre-existing infrastructure such as VPC subnets and security groups, and KMS keys for encryption. They focus on configuring the cache rather than provisioning the surrounding network infrastructure.

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

  • Snapshot restoration (snapshotArnsToRestores)
  • User group authentication (userGroupId)
  • Custom tags and metadata
  • Connection endpoint configuration

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

Let's create AWS ElastiCache Serverless Caches

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

Try Pulumi Cloud for FREE

Frequently Asked Questions

Engine Selection & Features
What cache engines can I use with ElastiCache Serverless?
You can use memcached, redis, or valkey as the cache engine.
Which engines support snapshot and backup features?
Only redis and valkey support snapshots. The dailySnapshotTime, snapshotRetentionLimit, and snapshotArnsToRestores properties are only available for these engine types.
Can I use user groups with all engine types?
No, the userGroupId property is only available for Redis and Valkey engines. It defaults to NULL if not specified.
Snapshots & Backups
How do I configure daily snapshots for my cache?
Set dailySnapshotTime to specify when snapshots are created (defaults to 0). Use snapshotRetentionLimit to control how many snapshots are retained before older ones are deleted on a rolling basis. Both properties only work with redis or valkey engines.
Can I restore a serverless cache from an existing snapshot?
Yes, use the snapshotArnsToRestores property with a list of snapshot ARNs. This is only supported for redis or valkey engines.
Networking & Security
Do all my subnets need to be in the same VPC?
Yes, all subnet IDs in the subnetIds list must belong to the same VPC.
What security groups are used if I don't specify any?
If no security group information is provided, the VPC’s Default Security Group associated with the cluster VPC endpoint will be used.
What happens if I don't provide a KMS key for encryption?
If you don’t specify a kmsKeyId, a default service key will be used for encrypting data at rest.
Resource Limits & Configuration
How do I set resource limits for my serverless cache?
Use the cacheUsageLimits property to configure storage limits (via dataStorage with maximum and unit) and ElastiCache Processing Units (via ecpuPerSeconds with maximum). For example, you can set a 10 GB storage limit and 5000 ECPU per second maximum.

Using a different cloud?

Explore database guides for other cloud providers: