The aws:rds/cluster:Cluster resource, part of the Pulumi AWS provider, defines an RDS Aurora cluster or Multi-AZ DB cluster: its engine type, availability zones, backup configuration, and scaling behavior. This guide focuses on four capabilities: Aurora MySQL and PostgreSQL clusters, Multi-AZ clusters with provisioned IOPS, Serverless v2 auto-scaling, and Secrets Manager password management.
RDS clusters depend on VPC infrastructure and are typically paired with ClusterInstance resources to define compute capacity. The examples are intentionally small. Combine them with your own VPC configuration, security groups, and instance definitions.
Create an Aurora MySQL cluster with backups
Most Aurora deployments start with a basic cluster that specifies the engine, availability zones, and backup settings.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const _default = new aws.rds.Cluster("default", {
clusterIdentifier: "aurora-cluster-demo",
engine: aws.rds.EngineType.AuroraMysql,
engineVersion: "5.7.mysql_aurora.2.03.2",
availabilityZones: [
"us-west-2a",
"us-west-2b",
"us-west-2c",
],
databaseName: "mydb",
masterUsername: "foo",
masterPassword: "must_be_eight_characters",
backupRetentionPeriod: 5,
preferredBackupWindow: "07:00-09:00",
});
import pulumi
import pulumi_aws as aws
default = aws.rds.Cluster("default",
cluster_identifier="aurora-cluster-demo",
engine=aws.rds.EngineType.AURORA_MYSQL,
engine_version="5.7.mysql_aurora.2.03.2",
availability_zones=[
"us-west-2a",
"us-west-2b",
"us-west-2c",
],
database_name="mydb",
master_username="foo",
master_password="must_be_eight_characters",
backup_retention_period=5,
preferred_backup_window="07:00-09:00")
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/rds"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := rds.NewCluster(ctx, "default", &rds.ClusterArgs{
ClusterIdentifier: pulumi.String("aurora-cluster-demo"),
Engine: pulumi.String(rds.EngineTypeAuroraMysql),
EngineVersion: pulumi.String("5.7.mysql_aurora.2.03.2"),
AvailabilityZones: pulumi.StringArray{
pulumi.String("us-west-2a"),
pulumi.String("us-west-2b"),
pulumi.String("us-west-2c"),
},
DatabaseName: pulumi.String("mydb"),
MasterUsername: pulumi.String("foo"),
MasterPassword: pulumi.String("must_be_eight_characters"),
BackupRetentionPeriod: pulumi.Int(5),
PreferredBackupWindow: pulumi.String("07:00-09:00"),
})
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 @default = new Aws.Rds.Cluster("default", new()
{
ClusterIdentifier = "aurora-cluster-demo",
Engine = Aws.Rds.EngineType.AuroraMysql,
EngineVersion = "5.7.mysql_aurora.2.03.2",
AvailabilityZones = new[]
{
"us-west-2a",
"us-west-2b",
"us-west-2c",
},
DatabaseName = "mydb",
MasterUsername = "foo",
MasterPassword = "must_be_eight_characters",
BackupRetentionPeriod = 5,
PreferredBackupWindow = "07:00-09:00",
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.rds.Cluster;
import com.pulumi.aws.rds.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 default_ = new Cluster("default", ClusterArgs.builder()
.clusterIdentifier("aurora-cluster-demo")
.engine("aurora-mysql")
.engineVersion("5.7.mysql_aurora.2.03.2")
.availabilityZones(
"us-west-2a",
"us-west-2b",
"us-west-2c")
.databaseName("mydb")
.masterUsername("foo")
.masterPassword("must_be_eight_characters")
.backupRetentionPeriod(5)
.preferredBackupWindow("07:00-09:00")
.build());
}
}
resources:
default:
type: aws:rds:Cluster
properties:
clusterIdentifier: aurora-cluster-demo
engine: aurora-mysql
engineVersion: 5.7.mysql_aurora.2.03.2
availabilityZones:
- us-west-2a
- us-west-2b
- us-west-2c
databaseName: mydb
masterUsername: foo
masterPassword: must_be_eight_characters
backupRetentionPeriod: 5
preferredBackupWindow: 07:00-09:00
The engine and engineVersion properties select Aurora MySQL 5.7. The availabilityZones array distributes storage across three zones for high availability. The backupRetentionPeriod and preferredBackupWindow properties control automated backups: this cluster retains backups for 5 days and runs them between 7:00 and 9:00 UTC. Without additional configuration, the cluster uses the default VPC and stores the master password in Pulumi state.
Create an Aurora PostgreSQL cluster
Teams running PostgreSQL workloads can use Aurora PostgreSQL for managed replication and automatic failover.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const postgresql = new aws.rds.Cluster("postgresql", {
clusterIdentifier: "aurora-cluster-demo",
engine: aws.rds.EngineType.AuroraPostgresql,
availabilityZones: [
"us-west-2a",
"us-west-2b",
"us-west-2c",
],
databaseName: "mydb",
masterUsername: "foo",
masterPassword: "must_be_eight_characters",
backupRetentionPeriod: 5,
preferredBackupWindow: "07:00-09:00",
});
import pulumi
import pulumi_aws as aws
postgresql = aws.rds.Cluster("postgresql",
cluster_identifier="aurora-cluster-demo",
engine=aws.rds.EngineType.AURORA_POSTGRESQL,
availability_zones=[
"us-west-2a",
"us-west-2b",
"us-west-2c",
],
database_name="mydb",
master_username="foo",
master_password="must_be_eight_characters",
backup_retention_period=5,
preferred_backup_window="07:00-09:00")
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/rds"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := rds.NewCluster(ctx, "postgresql", &rds.ClusterArgs{
ClusterIdentifier: pulumi.String("aurora-cluster-demo"),
Engine: pulumi.String(rds.EngineTypeAuroraPostgresql),
AvailabilityZones: pulumi.StringArray{
pulumi.String("us-west-2a"),
pulumi.String("us-west-2b"),
pulumi.String("us-west-2c"),
},
DatabaseName: pulumi.String("mydb"),
MasterUsername: pulumi.String("foo"),
MasterPassword: pulumi.String("must_be_eight_characters"),
BackupRetentionPeriod: pulumi.Int(5),
PreferredBackupWindow: pulumi.String("07:00-09:00"),
})
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 postgresql = new Aws.Rds.Cluster("postgresql", new()
{
ClusterIdentifier = "aurora-cluster-demo",
Engine = Aws.Rds.EngineType.AuroraPostgresql,
AvailabilityZones = new[]
{
"us-west-2a",
"us-west-2b",
"us-west-2c",
},
DatabaseName = "mydb",
MasterUsername = "foo",
MasterPassword = "must_be_eight_characters",
BackupRetentionPeriod = 5,
PreferredBackupWindow = "07:00-09:00",
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.rds.Cluster;
import com.pulumi.aws.rds.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 postgresql = new Cluster("postgresql", ClusterArgs.builder()
.clusterIdentifier("aurora-cluster-demo")
.engine("aurora-postgresql")
.availabilityZones(
"us-west-2a",
"us-west-2b",
"us-west-2c")
.databaseName("mydb")
.masterUsername("foo")
.masterPassword("must_be_eight_characters")
.backupRetentionPeriod(5)
.preferredBackupWindow("07:00-09:00")
.build());
}
}
resources:
postgresql:
type: aws:rds:Cluster
properties:
clusterIdentifier: aurora-cluster-demo
engine: aurora-postgresql
availabilityZones:
- us-west-2a
- us-west-2b
- us-west-2c
databaseName: mydb
masterUsername: foo
masterPassword: must_be_eight_characters
backupRetentionPeriod: 5
preferredBackupWindow: 07:00-09:00
Setting engine to AuroraPostgresql switches from MySQL to PostgreSQL compatibility. The cluster structure remains the same: availability zones, backup configuration, and credentials. Aurora handles replication and failover automatically across the specified zones.
Create a Multi-AZ RDS cluster with provisioned IOPS
Multi-AZ RDS clusters provide high availability for MySQL and PostgreSQL with automatic failover. Unlike Aurora, these clusters require explicit storage and compute configuration.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const example = new aws.rds.Cluster("example", {
clusterIdentifier: "example",
availabilityZones: [
"us-west-2a",
"us-west-2b",
"us-west-2c",
],
engine: aws.rds.EngineType.Mysql,
dbClusterInstanceClass: "db.r6gd.xlarge",
storageType: "io1",
allocatedStorage: 100,
iops: 1000,
masterUsername: "test",
masterPassword: "mustbeeightcharaters",
});
import pulumi
import pulumi_aws as aws
example = aws.rds.Cluster("example",
cluster_identifier="example",
availability_zones=[
"us-west-2a",
"us-west-2b",
"us-west-2c",
],
engine=aws.rds.EngineType.MYSQL,
db_cluster_instance_class="db.r6gd.xlarge",
storage_type="io1",
allocated_storage=100,
iops=1000,
master_username="test",
master_password="mustbeeightcharaters")
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/rds"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := rds.NewCluster(ctx, "example", &rds.ClusterArgs{
ClusterIdentifier: pulumi.String("example"),
AvailabilityZones: pulumi.StringArray{
pulumi.String("us-west-2a"),
pulumi.String("us-west-2b"),
pulumi.String("us-west-2c"),
},
Engine: pulumi.String(rds.EngineTypeMysql),
DbClusterInstanceClass: pulumi.String("db.r6gd.xlarge"),
StorageType: pulumi.String("io1"),
AllocatedStorage: pulumi.Int(100),
Iops: pulumi.Int(1000),
MasterUsername: pulumi.String("test"),
MasterPassword: pulumi.String("mustbeeightcharaters"),
})
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.Rds.Cluster("example", new()
{
ClusterIdentifier = "example",
AvailabilityZones = new[]
{
"us-west-2a",
"us-west-2b",
"us-west-2c",
},
Engine = Aws.Rds.EngineType.Mysql,
DbClusterInstanceClass = "db.r6gd.xlarge",
StorageType = "io1",
AllocatedStorage = 100,
Iops = 1000,
MasterUsername = "test",
MasterPassword = "mustbeeightcharaters",
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.rds.Cluster;
import com.pulumi.aws.rds.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()
.clusterIdentifier("example")
.availabilityZones(
"us-west-2a",
"us-west-2b",
"us-west-2c")
.engine("mysql")
.dbClusterInstanceClass("db.r6gd.xlarge")
.storageType("io1")
.allocatedStorage(100)
.iops(1000)
.masterUsername("test")
.masterPassword("mustbeeightcharaters")
.build());
}
}
resources:
example:
type: aws:rds:Cluster
properties:
clusterIdentifier: example
availabilityZones:
- us-west-2a
- us-west-2b
- us-west-2c
engine: mysql
dbClusterInstanceClass: db.r6gd.xlarge
storageType: io1
allocatedStorage: 100
iops: 1000
masterUsername: test
masterPassword: mustbeeightcharaters
The dbClusterInstanceClass property defines the compute capacity for each instance in the cluster. The storageType, allocatedStorage, and iops properties configure provisioned IOPS storage: this cluster allocates 100 GiB with 1,000 IOPS. Multi-AZ clusters use standard MySQL or PostgreSQL engines, not Aurora-specific engines.
Configure Serverless v2 with auto-scaling
Serverless v2 clusters automatically scale compute capacity based on workload demand, eliminating the need to provision fixed instance sizes.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const example = new aws.rds.Cluster("example", {
clusterIdentifier: "example",
engine: aws.rds.EngineType.AuroraPostgresql,
engineMode: aws.rds.EngineMode.Provisioned,
engineVersion: "13.6",
databaseName: "test",
masterUsername: "test",
masterPassword: "must_be_eight_characters",
storageEncrypted: true,
serverlessv2ScalingConfiguration: {
maxCapacity: 1,
minCapacity: 0,
secondsUntilAutoPause: 3600,
},
});
const exampleClusterInstance = new aws.rds.ClusterInstance("example", {
clusterIdentifier: example.id,
instanceClass: "db.serverless",
engine: example.engine.apply((x) => aws.rds.EngineType[x]),
engineVersion: example.engineVersion,
});
import pulumi
import pulumi_aws as aws
example = aws.rds.Cluster("example",
cluster_identifier="example",
engine=aws.rds.EngineType.AURORA_POSTGRESQL,
engine_mode=aws.rds.EngineMode.PROVISIONED,
engine_version="13.6",
database_name="test",
master_username="test",
master_password="must_be_eight_characters",
storage_encrypted=True,
serverlessv2_scaling_configuration={
"max_capacity": 1,
"min_capacity": 0,
"seconds_until_auto_pause": 3600,
})
example_cluster_instance = aws.rds.ClusterInstance("example",
cluster_identifier=example.id,
instance_class="db.serverless",
engine=example.engine,
engine_version=example.engine_version)
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/rds"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
example, err := rds.NewCluster(ctx, "example", &rds.ClusterArgs{
ClusterIdentifier: pulumi.String("example"),
Engine: pulumi.String(rds.EngineTypeAuroraPostgresql),
EngineMode: pulumi.String(rds.EngineModeProvisioned),
EngineVersion: pulumi.String("13.6"),
DatabaseName: pulumi.String("test"),
MasterUsername: pulumi.String("test"),
MasterPassword: pulumi.String("must_be_eight_characters"),
StorageEncrypted: pulumi.Bool(true),
Serverlessv2ScalingConfiguration: &rds.ClusterServerlessv2ScalingConfigurationArgs{
MaxCapacity: pulumi.Float64(1),
MinCapacity: pulumi.Float64(0),
SecondsUntilAutoPause: pulumi.Int(3600),
},
})
if err != nil {
return err
}
_, err = rds.NewClusterInstance(ctx, "example", &rds.ClusterInstanceArgs{
ClusterIdentifier: example.ID(),
InstanceClass: pulumi.String("db.serverless"),
Engine: example.Engine.ApplyT(func(x *string) rds.EngineType { return rds.EngineType(*x) }).(rds.EngineTypeOutput),
EngineVersion: example.EngineVersion,
})
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.Rds.Cluster("example", new()
{
ClusterIdentifier = "example",
Engine = Aws.Rds.EngineType.AuroraPostgresql,
EngineMode = Aws.Rds.EngineMode.Provisioned,
EngineVersion = "13.6",
DatabaseName = "test",
MasterUsername = "test",
MasterPassword = "must_be_eight_characters",
StorageEncrypted = true,
Serverlessv2ScalingConfiguration = new Aws.Rds.Inputs.ClusterServerlessv2ScalingConfigurationArgs
{
MaxCapacity = 1,
MinCapacity = 0,
SecondsUntilAutoPause = 3600,
},
});
var exampleClusterInstance = new Aws.Rds.ClusterInstance("example", new()
{
ClusterIdentifier = example.Id,
InstanceClass = "db.serverless",
Engine = example.Engine.Apply(System.Enum.Parse<Aws.Rds.EngineType>),
EngineVersion = example.EngineVersion,
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.rds.Cluster;
import com.pulumi.aws.rds.ClusterArgs;
import com.pulumi.aws.rds.inputs.ClusterServerlessv2ScalingConfigurationArgs;
import com.pulumi.aws.rds.ClusterInstance;
import com.pulumi.aws.rds.ClusterInstanceArgs;
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()
.clusterIdentifier("example")
.engine("aurora-postgresql")
.engineMode("provisioned")
.engineVersion("13.6")
.databaseName("test")
.masterUsername("test")
.masterPassword("must_be_eight_characters")
.storageEncrypted(true)
.serverlessv2ScalingConfiguration(ClusterServerlessv2ScalingConfigurationArgs.builder()
.maxCapacity(1.0)
.minCapacity(0.0)
.secondsUntilAutoPause(3600)
.build())
.build());
var exampleClusterInstance = new ClusterInstance("exampleClusterInstance", ClusterInstanceArgs.builder()
.clusterIdentifier(example.id())
.instanceClass("db.serverless")
.engine(example.engine())
.engineVersion(example.engineVersion())
.build());
}
}
resources:
example:
type: aws:rds:Cluster
properties:
clusterIdentifier: example
engine: aurora-postgresql
engineMode: provisioned
engineVersion: '13.6'
databaseName: test
masterUsername: test
masterPassword: must_be_eight_characters
storageEncrypted: true
serverlessv2ScalingConfiguration:
maxCapacity: 1
minCapacity: 0
secondsUntilAutoPause: 3600
exampleClusterInstance:
type: aws:rds:ClusterInstance
name: example
properties:
clusterIdentifier: ${example.id}
instanceClass: db.serverless
engine: ${example.engine}
engineVersion: ${example.engineVersion}
The engineMode must be set to provisioned (not serverless) for Serverless v2. The serverlessv2ScalingConfiguration block defines capacity limits: minCapacity and maxCapacity control the range of Aurora Capacity Units (ACUs) the cluster can scale between. Unlike the basic examples, Serverless v2 requires a separate ClusterInstance resource with instanceClass set to db.serverless. The cluster scales automatically within the configured range based on CPU and connection metrics.
Manage master password with Secrets Manager
Instead of storing passwords in Pulumi state, RDS can generate and rotate master passwords automatically using AWS Secrets Manager.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const test = new aws.rds.Cluster("test", {
clusterIdentifier: "example",
databaseName: "test",
manageMasterUserPassword: true,
masterUsername: "test",
});
import pulumi
import pulumi_aws as aws
test = aws.rds.Cluster("test",
cluster_identifier="example",
database_name="test",
manage_master_user_password=True,
master_username="test")
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/rds"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := rds.NewCluster(ctx, "test", &rds.ClusterArgs{
ClusterIdentifier: pulumi.String("example"),
DatabaseName: pulumi.String("test"),
ManageMasterUserPassword: pulumi.Bool(true),
MasterUsername: pulumi.String("test"),
})
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.Rds.Cluster("test", new()
{
ClusterIdentifier = "example",
DatabaseName = "test",
ManageMasterUserPassword = true,
MasterUsername = "test",
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.rds.Cluster;
import com.pulumi.aws.rds.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 test = new Cluster("test", ClusterArgs.builder()
.clusterIdentifier("example")
.databaseName("test")
.manageMasterUserPassword(true)
.masterUsername("test")
.build());
}
}
resources:
test:
type: aws:rds:Cluster
properties:
clusterIdentifier: example
databaseName: test
manageMasterUserPassword: true
masterUsername: test
Setting manageMasterUserPassword to true delegates password creation and rotation to Secrets Manager. You omit the masterPassword property entirely. RDS generates a strong password, stores it in Secrets Manager, and rotates it automatically. This removes credentials from your Pulumi state file and enables automatic rotation policies.
Restore a global cluster from snapshot
Global clusters span multiple AWS regions for disaster recovery and low-latency reads. When building from a snapshot, you must restore the cluster first, then attach it to the global cluster.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const example = aws.rds.getClusterSnapshot({
dbClusterIdentifier: "example-original-cluster",
mostRecent: true,
});
const exampleCluster = new aws.rds.Cluster("example", {
engine: aws.rds.EngineType.Aurora,
engineVersion: "5.6.mysql_aurora.1.22.4",
clusterIdentifier: "example",
snapshotIdentifier: example.then(example => example.id),
});
const exampleGlobalCluster = new aws.rds.GlobalCluster("example", {
globalClusterIdentifier: "example",
sourceDbClusterIdentifier: exampleCluster.arn,
forceDestroy: true,
});
import pulumi
import pulumi_aws as aws
example = aws.rds.get_cluster_snapshot(db_cluster_identifier="example-original-cluster",
most_recent=True)
example_cluster = aws.rds.Cluster("example",
engine=aws.rds.EngineType.AURORA,
engine_version="5.6.mysql_aurora.1.22.4",
cluster_identifier="example",
snapshot_identifier=example.id)
example_global_cluster = aws.rds.GlobalCluster("example",
global_cluster_identifier="example",
source_db_cluster_identifier=example_cluster.arn,
force_destroy=True)
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/rds"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
example, err := rds.LookupClusterSnapshot(ctx, &rds.LookupClusterSnapshotArgs{
DbClusterIdentifier: pulumi.StringRef("example-original-cluster"),
MostRecent: pulumi.BoolRef(true),
}, nil)
if err != nil {
return err
}
exampleCluster, err := rds.NewCluster(ctx, "example", &rds.ClusterArgs{
Engine: pulumi.String(rds.EngineTypeAurora),
EngineVersion: pulumi.String("5.6.mysql_aurora.1.22.4"),
ClusterIdentifier: pulumi.String("example"),
SnapshotIdentifier: pulumi.String(example.Id),
})
if err != nil {
return err
}
_, err = rds.NewGlobalCluster(ctx, "example", &rds.GlobalClusterArgs{
GlobalClusterIdentifier: pulumi.String("example"),
SourceDbClusterIdentifier: exampleCluster.Arn,
ForceDestroy: pulumi.Bool(true),
})
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.Rds.GetClusterSnapshot.Invoke(new()
{
DbClusterIdentifier = "example-original-cluster",
MostRecent = true,
});
var exampleCluster = new Aws.Rds.Cluster("example", new()
{
Engine = Aws.Rds.EngineType.Aurora,
EngineVersion = "5.6.mysql_aurora.1.22.4",
ClusterIdentifier = "example",
SnapshotIdentifier = example.Apply(getClusterSnapshotResult => getClusterSnapshotResult.Id),
});
var exampleGlobalCluster = new Aws.Rds.GlobalCluster("example", new()
{
GlobalClusterIdentifier = "example",
SourceDbClusterIdentifier = exampleCluster.Arn,
ForceDestroy = true,
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.rds.RdsFunctions;
import com.pulumi.aws.rds.inputs.GetClusterSnapshotArgs;
import com.pulumi.aws.rds.Cluster;
import com.pulumi.aws.rds.ClusterArgs;
import com.pulumi.aws.rds.GlobalCluster;
import com.pulumi.aws.rds.GlobalClusterArgs;
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 = RdsFunctions.getClusterSnapshot(GetClusterSnapshotArgs.builder()
.dbClusterIdentifier("example-original-cluster")
.mostRecent(true)
.build());
var exampleCluster = new Cluster("exampleCluster", ClusterArgs.builder()
.engine("aurora")
.engineVersion("5.6.mysql_aurora.1.22.4")
.clusterIdentifier("example")
.snapshotIdentifier(example.id())
.build());
var exampleGlobalCluster = new GlobalCluster("exampleGlobalCluster", GlobalClusterArgs.builder()
.globalClusterIdentifier("example")
.sourceDbClusterIdentifier(exampleCluster.arn())
.forceDestroy(true)
.build());
}
}
resources:
exampleCluster:
type: aws:rds:Cluster
name: example
properties:
engine: aurora
engineVersion: 5.6.mysql_aurora.1.22.4
clusterIdentifier: example
snapshotIdentifier: ${example.id}
exampleGlobalCluster:
type: aws:rds:GlobalCluster
name: example
properties:
globalClusterIdentifier: example
sourceDbClusterIdentifier: ${exampleCluster.arn}
forceDestroy: true
variables:
example:
fn::invoke:
function: aws:rds:getClusterSnapshot
arguments:
dbClusterIdentifier: example-original-cluster
mostRecent: true
The getClusterSnapshot function retrieves the most recent snapshot from an existing cluster. The snapshotIdentifier property restores the cluster from that snapshot. After the cluster is created, the GlobalCluster resource references it via sourceDbClusterIdentifier to establish the global cluster. This two-step process is required: you cannot restore from snapshot and join a global cluster in a single operation.
Beyond these examples
These snippets focus on specific cluster-level features: Aurora and Multi-AZ cluster types, Serverless v2 auto-scaling, Secrets Manager password management, and global clusters and snapshot restoration. They’re intentionally minimal rather than full database deployments.
The examples may reference pre-existing infrastructure such as VPC, subnets, and security groups (most examples use defaults), DB snapshots (for restoration examples), and IAM permissions for Secrets Manager. They focus on configuring the cluster rather than provisioning the surrounding network infrastructure.
To keep things focused, common cluster patterns are omitted, including:
- Storage encryption (storageEncrypted, kmsKeyId)
- Network configuration (vpcSecurityGroupIds, dbSubnetGroupName)
- Performance Insights and Enhanced Monitoring
- Cluster parameter groups and instance parameter groups
- IAM database authentication
- CloudWatch log exports
These omissions are intentional: the goal is to illustrate how each cluster feature is wired, not provide drop-in database modules. See the RDS Cluster resource reference for all available configuration options.
Let's create AWS RDS Aurora Clusters
Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.
Try Pulumi Cloud for FREEFrequently Asked Questions
Cluster Types & Configuration
aurora-mysql or aurora-postgresql, while Multi-AZ RDS clusters use mysql or postgres. Multi-AZ clusters require additional properties: storage_type, allocated_storage, iops, and db_cluster_instance_class.engine_mode to provisioned (not serverless), configure serverlessv2_scaling_configuration, and add an aws.rds.ClusterInstance with instance_class set to db.serverless. Note that storage_encrypted defaults to false for provisioned mode, unlike Serverless v1.engine_mode set to serverless with storage_encrypted defaulting to true. Serverless v2 uses engine_mode set to provisioned with storage_encrypted defaulting to false, and requires explicit serverlessv2_scaling_configuration and cluster instances.aurora and aurora-mysql engines support backtracking. Set backtrack_window between 0 and 259200 seconds (72 hours). Default is 0 (disabled).Security & Credentials
master_username and master_password are stored in plain-text in the raw state. To avoid this, use manage_master_user_password set to true, which stores the password in AWS Secrets Manager instead.manage_master_user_password to true to use Secrets Manager, or provide master_password directly. When switching to managed passwords, you must remove the master_password attribute.iam_roles attribute on the cluster. Using both causes conflicts and overwrites. Choose one approach and stick with it.provisioned engine_mode, storage_encrypted defaults to false. For serverless engine_mode, it defaults to true. When restoring from an unencrypted snapshot, you must provide kms_key_id to encrypt the restored cluster.Maintenance & Updates
apply_immediately to true causes brief downtime as the server reboots. Updating engine_version also results in an outage. By default, changes are applied during the next maintenance window to minimize disruption.apply_immediately is false), modifications are applied during the next maintenance window. Set apply_immediately to true to apply changes immediately, but this may cause downtime.Snapshots & Backups
snapshot_identifier conflicts with global_cluster_identifier. You must restore from the snapshot first, then join the global cluster in a separate operation.skip_final_snapshot to true. By default, it’s false, which creates a final snapshot using the name from final_snapshot_identifier before deletion.Networking & Availability
lifecycle with ignore_changes for availability_zones.db_subnet_group_name on the cluster must match the value specified on every aws.rds.ClusterInstance in the cluster. Mismatches cause configuration errors.Common Errors & Gotchas
availability_zones, cluster_identifier, cluster_identifier_prefix, database_name, db_subnet_group_name, db_system_id, engine, engine_mode, kms_key_id, master_username, restore_to_point_in_time, snapshot_identifier, source_region, storage_encrypted, and cluster_scalability_type.master_username does not support in-place updates and cannot be changed during a restore from snapshot.ca_certificate_identifier property is only supported for Multi-AZ DB clusters (engines mysql or postgres), not Aurora clusters.