Create AWS RDS Global Clusters

The aws:rds/globalCluster:GlobalCluster resource, part of the Pulumi AWS provider, defines an Aurora global database that spans multiple AWS regions with a primary writer cluster and read-only secondary clusters connected via Aurora storage-level replication. This guide focuses on three capabilities: creating new global clusters with cross-region replication, promoting existing regional clusters to global, and coordinating engine version upgrades.

Global clusters require regional Aurora clusters and cluster instances in each participating region, along with subnet groups and multi-region provider configuration. The examples are intentionally small. Combine them with your own VPC infrastructure, IAM roles, and monitoring configuration.

Create a MySQL global cluster with primary and secondary regions

Teams building globally distributed applications start with Aurora MySQL global clusters to replicate data across regions for disaster recovery and low-latency reads.

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

const example = new aws.rds.GlobalCluster("example", {
    globalClusterIdentifier: "global-test",
    engine: "aurora",
    engineVersion: "5.6.mysql_aurora.1.22.2",
    databaseName: "example_db",
});
const primary = new aws.rds.Cluster("primary", {
    engine: example.engine,
    engineVersion: example.engineVersion,
    clusterIdentifier: "test-primary-cluster",
    masterUsername: "username",
    masterPassword: "somepass123",
    databaseName: "example_db",
    globalClusterIdentifier: example.id,
    dbSubnetGroupName: "default",
});
const primaryClusterInstance = new aws.rds.ClusterInstance("primary", {
    engine: example.engine.apply((x) => aws.rds.EngineType[x]),
    engineVersion: example.engineVersion,
    identifier: "test-primary-cluster-instance",
    clusterIdentifier: primary.id,
    instanceClass: aws.rds.InstanceType.R4_Large,
    dbSubnetGroupName: "default",
});
const secondary = new aws.rds.Cluster("secondary", {
    engine: example.engine,
    engineVersion: example.engineVersion,
    clusterIdentifier: "test-secondary-cluster",
    globalClusterIdentifier: example.id,
    dbSubnetGroupName: "default",
}, {
    dependsOn: [primaryClusterInstance],
});
const secondaryClusterInstance = new aws.rds.ClusterInstance("secondary", {
    engine: example.engine.apply((x) => aws.rds.EngineType[x]),
    engineVersion: example.engineVersion,
    identifier: "test-secondary-cluster-instance",
    clusterIdentifier: secondary.id,
    instanceClass: aws.rds.InstanceType.R4_Large,
    dbSubnetGroupName: "default",
});
import pulumi
import pulumi_aws as aws

example = aws.rds.GlobalCluster("example",
    global_cluster_identifier="global-test",
    engine="aurora",
    engine_version="5.6.mysql_aurora.1.22.2",
    database_name="example_db")
primary = aws.rds.Cluster("primary",
    engine=example.engine,
    engine_version=example.engine_version,
    cluster_identifier="test-primary-cluster",
    master_username="username",
    master_password="somepass123",
    database_name="example_db",
    global_cluster_identifier=example.id,
    db_subnet_group_name="default")
primary_cluster_instance = aws.rds.ClusterInstance("primary",
    engine=example.engine.apply(lambda x: aws.rds.EngineType(x)),
    engine_version=example.engine_version,
    identifier="test-primary-cluster-instance",
    cluster_identifier=primary.id,
    instance_class=aws.rds.InstanceType.R4_LARGE,
    db_subnet_group_name="default")
secondary = aws.rds.Cluster("secondary",
    engine=example.engine,
    engine_version=example.engine_version,
    cluster_identifier="test-secondary-cluster",
    global_cluster_identifier=example.id,
    db_subnet_group_name="default",
    opts = pulumi.ResourceOptions(depends_on=[primary_cluster_instance]))
secondary_cluster_instance = aws.rds.ClusterInstance("secondary",
    engine=example.engine.apply(lambda x: aws.rds.EngineType(x)),
    engine_version=example.engine_version,
    identifier="test-secondary-cluster-instance",
    cluster_identifier=secondary.id,
    instance_class=aws.rds.InstanceType.R4_LARGE,
    db_subnet_group_name="default")
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.NewGlobalCluster(ctx, "example", &rds.GlobalClusterArgs{
			GlobalClusterIdentifier: pulumi.String("global-test"),
			Engine:                  pulumi.String("aurora"),
			EngineVersion:           pulumi.String("5.6.mysql_aurora.1.22.2"),
			DatabaseName:            pulumi.String("example_db"),
		})
		if err != nil {
			return err
		}
		primary, err := rds.NewCluster(ctx, "primary", &rds.ClusterArgs{
			Engine:                  example.Engine,
			EngineVersion:           example.EngineVersion,
			ClusterIdentifier:       pulumi.String("test-primary-cluster"),
			MasterUsername:          pulumi.String("username"),
			MasterPassword:          pulumi.String("somepass123"),
			DatabaseName:            pulumi.String("example_db"),
			GlobalClusterIdentifier: example.ID(),
			DbSubnetGroupName:       pulumi.String("default"),
		})
		if err != nil {
			return err
		}
		primaryClusterInstance, err := rds.NewClusterInstance(ctx, "primary", &rds.ClusterInstanceArgs{
			Engine:            example.Engine.ApplyT(func(x *string) rds.EngineType { return rds.EngineType(*x) }).(rds.EngineTypeOutput),
			EngineVersion:     example.EngineVersion,
			Identifier:        pulumi.String("test-primary-cluster-instance"),
			ClusterIdentifier: primary.ID(),
			InstanceClass:     pulumi.String(rds.InstanceType_R4_Large),
			DbSubnetGroupName: pulumi.String("default"),
		})
		if err != nil {
			return err
		}
		secondary, err := rds.NewCluster(ctx, "secondary", &rds.ClusterArgs{
			Engine:                  example.Engine,
			EngineVersion:           example.EngineVersion,
			ClusterIdentifier:       pulumi.String("test-secondary-cluster"),
			GlobalClusterIdentifier: example.ID(),
			DbSubnetGroupName:       pulumi.String("default"),
		}, pulumi.DependsOn([]pulumi.Resource{
			primaryClusterInstance,
		}))
		if err != nil {
			return err
		}
		_, err = rds.NewClusterInstance(ctx, "secondary", &rds.ClusterInstanceArgs{
			Engine:            example.Engine.ApplyT(func(x *string) rds.EngineType { return rds.EngineType(*x) }).(rds.EngineTypeOutput),
			EngineVersion:     example.EngineVersion,
			Identifier:        pulumi.String("test-secondary-cluster-instance"),
			ClusterIdentifier: secondary.ID(),
			InstanceClass:     pulumi.String(rds.InstanceType_R4_Large),
			DbSubnetGroupName: pulumi.String("default"),
		})
		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.GlobalCluster("example", new()
    {
        GlobalClusterIdentifier = "global-test",
        Engine = "aurora",
        EngineVersion = "5.6.mysql_aurora.1.22.2",
        DatabaseName = "example_db",
    });

    var primary = new Aws.Rds.Cluster("primary", new()
    {
        Engine = example.Engine,
        EngineVersion = example.EngineVersion,
        ClusterIdentifier = "test-primary-cluster",
        MasterUsername = "username",
        MasterPassword = "somepass123",
        DatabaseName = "example_db",
        GlobalClusterIdentifier = example.Id,
        DbSubnetGroupName = "default",
    });

    var primaryClusterInstance = new Aws.Rds.ClusterInstance("primary", new()
    {
        Engine = example.Engine.Apply(System.Enum.Parse<Aws.Rds.EngineType>),
        EngineVersion = example.EngineVersion,
        Identifier = "test-primary-cluster-instance",
        ClusterIdentifier = primary.Id,
        InstanceClass = Aws.Rds.InstanceType.R4_Large,
        DbSubnetGroupName = "default",
    });

    var secondary = new Aws.Rds.Cluster("secondary", new()
    {
        Engine = example.Engine,
        EngineVersion = example.EngineVersion,
        ClusterIdentifier = "test-secondary-cluster",
        GlobalClusterIdentifier = example.Id,
        DbSubnetGroupName = "default",
    }, new CustomResourceOptions
    {
        DependsOn =
        {
            primaryClusterInstance,
        },
    });

    var secondaryClusterInstance = new Aws.Rds.ClusterInstance("secondary", new()
    {
        Engine = example.Engine.Apply(System.Enum.Parse<Aws.Rds.EngineType>),
        EngineVersion = example.EngineVersion,
        Identifier = "test-secondary-cluster-instance",
        ClusterIdentifier = secondary.Id,
        InstanceClass = Aws.Rds.InstanceType.R4_Large,
        DbSubnetGroupName = "default",
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.rds.GlobalCluster;
import com.pulumi.aws.rds.GlobalClusterArgs;
import com.pulumi.aws.rds.Cluster;
import com.pulumi.aws.rds.ClusterArgs;
import com.pulumi.aws.rds.ClusterInstance;
import com.pulumi.aws.rds.ClusterInstanceArgs;
import com.pulumi.resources.CustomResourceOptions;
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 GlobalCluster("example", GlobalClusterArgs.builder()
            .globalClusterIdentifier("global-test")
            .engine("aurora")
            .engineVersion("5.6.mysql_aurora.1.22.2")
            .databaseName("example_db")
            .build());

        var primary = new Cluster("primary", ClusterArgs.builder()
            .engine(example.engine())
            .engineVersion(example.engineVersion())
            .clusterIdentifier("test-primary-cluster")
            .masterUsername("username")
            .masterPassword("somepass123")
            .databaseName("example_db")
            .globalClusterIdentifier(example.id())
            .dbSubnetGroupName("default")
            .build());

        var primaryClusterInstance = new ClusterInstance("primaryClusterInstance", ClusterInstanceArgs.builder()
            .engine(example.engine())
            .engineVersion(example.engineVersion())
            .identifier("test-primary-cluster-instance")
            .clusterIdentifier(primary.id())
            .instanceClass("db.r4.large")
            .dbSubnetGroupName("default")
            .build());

        var secondary = new Cluster("secondary", ClusterArgs.builder()
            .engine(example.engine())
            .engineVersion(example.engineVersion())
            .clusterIdentifier("test-secondary-cluster")
            .globalClusterIdentifier(example.id())
            .dbSubnetGroupName("default")
            .build(), CustomResourceOptions.builder()
                .dependsOn(primaryClusterInstance)
                .build());

        var secondaryClusterInstance = new ClusterInstance("secondaryClusterInstance", ClusterInstanceArgs.builder()
            .engine(example.engine())
            .engineVersion(example.engineVersion())
            .identifier("test-secondary-cluster-instance")
            .clusterIdentifier(secondary.id())
            .instanceClass("db.r4.large")
            .dbSubnetGroupName("default")
            .build());

    }
}
resources:
  example:
    type: aws:rds:GlobalCluster
    properties:
      globalClusterIdentifier: global-test
      engine: aurora
      engineVersion: 5.6.mysql_aurora.1.22.2
      databaseName: example_db
  primary:
    type: aws:rds:Cluster
    properties:
      engine: ${example.engine}
      engineVersion: ${example.engineVersion}
      clusterIdentifier: test-primary-cluster
      masterUsername: username
      masterPassword: somepass123
      databaseName: example_db
      globalClusterIdentifier: ${example.id}
      dbSubnetGroupName: default
  primaryClusterInstance:
    type: aws:rds:ClusterInstance
    name: primary
    properties:
      engine: ${example.engine}
      engineVersion: ${example.engineVersion}
      identifier: test-primary-cluster-instance
      clusterIdentifier: ${primary.id}
      instanceClass: db.r4.large
      dbSubnetGroupName: default
  secondary:
    type: aws:rds:Cluster
    properties:
      engine: ${example.engine}
      engineVersion: ${example.engineVersion}
      clusterIdentifier: test-secondary-cluster
      globalClusterIdentifier: ${example.id}
      dbSubnetGroupName: default
    options:
      dependsOn:
        - ${primaryClusterInstance}
  secondaryClusterInstance:
    type: aws:rds:ClusterInstance
    name: secondary
    properties:
      engine: ${example.engine}
      engineVersion: ${example.engineVersion}
      identifier: test-secondary-cluster-instance
      clusterIdentifier: ${secondary.id}
      instanceClass: db.r4.large
      dbSubnetGroupName: default

The GlobalCluster resource establishes the global database container. The primary Cluster receives writes and replicates to secondary regions through Aurora’s storage subsystem. The dependsOn relationship ensures the primary cluster instance exists before creating the secondary cluster, which is required for replication to begin. Each cluster needs its own ClusterInstance to handle queries.

Promote an existing cluster to global

Organizations with established regional Aurora clusters can promote them to global clusters without recreating the database or migrating data.

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

const example = new aws.rds.Cluster("example", {});
const exampleGlobalCluster = new aws.rds.GlobalCluster("example", {
    forceDestroy: true,
    globalClusterIdentifier: "example",
    sourceDbClusterIdentifier: example.arn,
});
import pulumi
import pulumi_aws as aws

example = aws.rds.Cluster("example")
example_global_cluster = aws.rds.GlobalCluster("example",
    force_destroy=True,
    global_cluster_identifier="example",
    source_db_cluster_identifier=example.arn)
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", nil)
		if err != nil {
			return err
		}
		_, err = rds.NewGlobalCluster(ctx, "example", &rds.GlobalClusterArgs{
			ForceDestroy:              pulumi.Bool(true),
			GlobalClusterIdentifier:   pulumi.String("example"),
			SourceDbClusterIdentifier: example.Arn,
		})
		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");

    var exampleGlobalCluster = new Aws.Rds.GlobalCluster("example", new()
    {
        ForceDestroy = true,
        GlobalClusterIdentifier = "example",
        SourceDbClusterIdentifier = example.Arn,
    });

});
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.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) {
        var example = new Cluster("example");

        var exampleGlobalCluster = new GlobalCluster("exampleGlobalCluster", GlobalClusterArgs.builder()
            .forceDestroy(true)
            .globalClusterIdentifier("example")
            .sourceDbClusterIdentifier(example.arn())
            .build());

    }
}
resources:
  example:
    type: aws:rds:Cluster
  exampleGlobalCluster:
    type: aws:rds:GlobalCluster
    name: example
    properties:
      forceDestroy: true
      globalClusterIdentifier: example
      sourceDbClusterIdentifier: ${example.arn}

The sourceDbClusterIdentifier property references an existing cluster’s ARN, converting it into the primary cluster of a new global database. The forceDestroy property allows Pulumi to remove member clusters when destroying the global cluster. After creation, you can remove sourceDbClusterIdentifier and add engine/engineVersion properties to enable version upgrades.

Upgrade engine versions across all regions

Global clusters require coordinated engine upgrades across all member clusters. Pulumi attempts in-place upgrades when you change the engineVersion property.

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

const example = new aws.rds.GlobalCluster("example", {
    globalClusterIdentifier: "kyivkharkiv",
    engine: "aurora-mysql",
    engineVersion: "5.7.mysql_aurora.2.07.5",
});
const primary = new aws.rds.Cluster("primary", {
    allowMajorVersionUpgrade: true,
    applyImmediately: true,
    clusterIdentifier: "odessadnipro",
    databaseName: "totoro",
    engine: example.engine,
    engineVersion: example.engineVersion,
    globalClusterIdentifier: example.id,
    masterPassword: "satsukimae",
    masterUsername: "maesatsuki",
    skipFinalSnapshot: true,
});
const primaryClusterInstance = new aws.rds.ClusterInstance("primary", {
    applyImmediately: true,
    clusterIdentifier: primary.id,
    engine: primary.engine.apply((x) => aws.rds.EngineType[x]),
    engineVersion: primary.engineVersion,
    identifier: "donetsklviv",
    instanceClass: aws.rds.InstanceType.R4_Large,
});
import pulumi
import pulumi_aws as aws

example = aws.rds.GlobalCluster("example",
    global_cluster_identifier="kyivkharkiv",
    engine="aurora-mysql",
    engine_version="5.7.mysql_aurora.2.07.5")
primary = aws.rds.Cluster("primary",
    allow_major_version_upgrade=True,
    apply_immediately=True,
    cluster_identifier="odessadnipro",
    database_name="totoro",
    engine=example.engine,
    engine_version=example.engine_version,
    global_cluster_identifier=example.id,
    master_password="satsukimae",
    master_username="maesatsuki",
    skip_final_snapshot=True)
primary_cluster_instance = aws.rds.ClusterInstance("primary",
    apply_immediately=True,
    cluster_identifier=primary.id,
    engine=primary.engine.apply(lambda x: aws.rds.EngineType(x)),
    engine_version=primary.engine_version,
    identifier="donetsklviv",
    instance_class=aws.rds.InstanceType.R4_LARGE)
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.NewGlobalCluster(ctx, "example", &rds.GlobalClusterArgs{
			GlobalClusterIdentifier: pulumi.String("kyivkharkiv"),
			Engine:                  pulumi.String("aurora-mysql"),
			EngineVersion:           pulumi.String("5.7.mysql_aurora.2.07.5"),
		})
		if err != nil {
			return err
		}
		primary, err := rds.NewCluster(ctx, "primary", &rds.ClusterArgs{
			AllowMajorVersionUpgrade: pulumi.Bool(true),
			ApplyImmediately:         pulumi.Bool(true),
			ClusterIdentifier:        pulumi.String("odessadnipro"),
			DatabaseName:             pulumi.String("totoro"),
			Engine:                   example.Engine,
			EngineVersion:            example.EngineVersion,
			GlobalClusterIdentifier:  example.ID(),
			MasterPassword:           pulumi.String("satsukimae"),
			MasterUsername:           pulumi.String("maesatsuki"),
			SkipFinalSnapshot:        pulumi.Bool(true),
		})
		if err != nil {
			return err
		}
		_, err = rds.NewClusterInstance(ctx, "primary", &rds.ClusterInstanceArgs{
			ApplyImmediately:  pulumi.Bool(true),
			ClusterIdentifier: primary.ID(),
			Engine:            primary.Engine.ApplyT(func(x *string) rds.EngineType { return rds.EngineType(*x) }).(rds.EngineTypeOutput),
			EngineVersion:     primary.EngineVersion,
			Identifier:        pulumi.String("donetsklviv"),
			InstanceClass:     pulumi.String(rds.InstanceType_R4_Large),
		})
		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.GlobalCluster("example", new()
    {
        GlobalClusterIdentifier = "kyivkharkiv",
        Engine = "aurora-mysql",
        EngineVersion = "5.7.mysql_aurora.2.07.5",
    });

    var primary = new Aws.Rds.Cluster("primary", new()
    {
        AllowMajorVersionUpgrade = true,
        ApplyImmediately = true,
        ClusterIdentifier = "odessadnipro",
        DatabaseName = "totoro",
        Engine = example.Engine,
        EngineVersion = example.EngineVersion,
        GlobalClusterIdentifier = example.Id,
        MasterPassword = "satsukimae",
        MasterUsername = "maesatsuki",
        SkipFinalSnapshot = true,
    });

    var primaryClusterInstance = new Aws.Rds.ClusterInstance("primary", new()
    {
        ApplyImmediately = true,
        ClusterIdentifier = primary.Id,
        Engine = primary.Engine.Apply(System.Enum.Parse<Aws.Rds.EngineType>),
        EngineVersion = primary.EngineVersion,
        Identifier = "donetsklviv",
        InstanceClass = Aws.Rds.InstanceType.R4_Large,
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.rds.GlobalCluster;
import com.pulumi.aws.rds.GlobalClusterArgs;
import com.pulumi.aws.rds.Cluster;
import com.pulumi.aws.rds.ClusterArgs;
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 GlobalCluster("example", GlobalClusterArgs.builder()
            .globalClusterIdentifier("kyivkharkiv")
            .engine("aurora-mysql")
            .engineVersion("5.7.mysql_aurora.2.07.5")
            .build());

        var primary = new Cluster("primary", ClusterArgs.builder()
            .allowMajorVersionUpgrade(true)
            .applyImmediately(true)
            .clusterIdentifier("odessadnipro")
            .databaseName("totoro")
            .engine(example.engine())
            .engineVersion(example.engineVersion())
            .globalClusterIdentifier(example.id())
            .masterPassword("satsukimae")
            .masterUsername("maesatsuki")
            .skipFinalSnapshot(true)
            .build());

        var primaryClusterInstance = new ClusterInstance("primaryClusterInstance", ClusterInstanceArgs.builder()
            .applyImmediately(true)
            .clusterIdentifier(primary.id())
            .engine(primary.engine())
            .engineVersion(primary.engineVersion())
            .identifier("donetsklviv")
            .instanceClass("db.r4.large")
            .build());

    }
}
resources:
  example:
    type: aws:rds:GlobalCluster
    properties:
      globalClusterIdentifier: kyivkharkiv
      engine: aurora-mysql
      engineVersion: 5.7.mysql_aurora.2.07.5
  primary:
    type: aws:rds:Cluster
    properties:
      allowMajorVersionUpgrade: true
      applyImmediately: true
      clusterIdentifier: odessadnipro
      databaseName: totoro
      engine: ${example.engine}
      engineVersion: ${example.engineVersion}
      globalClusterIdentifier: ${example.id}
      masterPassword: satsukimae
      masterUsername: maesatsuki
      skipFinalSnapshot: true
  primaryClusterInstance:
    type: aws:rds:ClusterInstance
    name: primary
    properties:
      applyImmediately: true
      clusterIdentifier: ${primary.id}
      engine: ${primary.engine}
      engineVersion: ${primary.engineVersion}
      identifier: donetsklviv
      instanceClass: db.r4.large

When you update engineVersion on the GlobalCluster, Pulumi upgrades all member clusters automatically. The allowMajorVersionUpgrade and applyImmediately properties on the Cluster resource control upgrade behavior. Use ignoreChanges for engineVersion on Cluster resources to avoid “inconsistent final plan” errors, since the GlobalCluster manages version updates.

Beyond these examples

These snippets focus on specific global cluster features: cross-region replication with primary and secondary clusters, promotion from existing regional clusters, and coordinated engine version upgrades. They’re intentionally minimal rather than full database deployments.

The examples rely on pre-existing infrastructure such as subnet groups in each region, provider configuration for secondary regions, and existing Aurora clusters for promotion scenarios. They focus on configuring the global cluster rather than provisioning all supporting infrastructure.

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

  • Encryption configuration (storageEncrypted, KMS keys)
  • Deletion protection and backup retention
  • Monitoring and performance insights
  • IAM database authentication

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

Let's create AWS RDS Global Clusters

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

Try Pulumi Cloud for FREE

Frequently Asked Questions

Engine Version Upgrades
Why am I getting an 'inconsistent final plan' error when upgrading my global cluster's engine version?
Upgrading engineVersion on the global cluster triggers automatic in-place upgrades of associated cluster members, which causes Pulumi to detect inconsistencies. Use ignoreChanges for engineVersion on your aws.rds.Cluster resources to avoid this error.
How do I upgrade the engine version of my global cluster?
Update engineVersion on the aws.rds.GlobalCluster resource. Set allowMajorVersionUpgrade: true and applyImmediately: true on your aws.rds.Cluster resources, and add ignoreChanges for engineVersion on the clusters to prevent plan inconsistencies.
Creation & Configuration
What database engines are supported for global clusters?
Global clusters support aurora (default), aurora-mysql, and aurora-postgresql. The engine, engineVersion, and instanceClass must together support global databases.
How do I create a global cluster from an existing cluster?
Set sourceDbClusterIdentifier to the ARN of your existing cluster and set forceDestroy: true. After creation, you can remove sourceDbClusterIdentifier and replace it with engine and engineVersion to enable version upgrades.
When is forceDestroy required?
forceDestroy is required when using sourceDbClusterIdentifier. It enables removal of DB cluster members from the global cluster on destroy.
What happens when I set both sourceDbClusterIdentifier and engine/engineVersion?
During creation, all engine-related values are ignored and the global cluster inherits engine and engineVersion from the source cluster. After the first apply, any differences between inherited and configured values trigger an in-place update.
Multi-Region Setup
How do I set up a global cluster with primary and secondary regions?
Create the aws.rds.GlobalCluster, then create the primary aws.rds.Cluster with globalClusterIdentifier. Create the primary aws.rds.ClusterInstance, then create the secondary aws.rds.Cluster with dependsOn: [primaryClusterInstance]. Finally, create the secondary aws.rds.ClusterInstance.
Why does my secondary cluster need to depend on the primary cluster instance?
The secondary cluster must wait for the primary cluster instance to be fully created before it can join the global cluster. Use dependsOn: [primaryClusterInstance] on the secondary cluster.
Import & Drift Detection
Why does Pulumi show a perpetual diff on sourceDbClusterIdentifier after import?
sourceDbClusterIdentifier has no API read method, so Pulumi can’t detect its current value. Either omit sourceDbClusterIdentifier from your program or use ignoreChanges to hide the difference.
Why does Pulumi show a diff for forceDestroy after importing?
forceDestroy only exists in Pulumi and isn’t stored in AWS. After import, Pulumi will show a difference on the first plan to update the state. This change is safe to apply immediately.
Immutability & Constraints
What properties can't be changed after creating a global cluster?
The following properties are immutable: databaseName, globalClusterIdentifier, engine, sourceDbClusterIdentifier, and storageEncrypted. Changing these requires recreating the global cluster.
What's the default encryption setting for global clusters?
storageEncrypted defaults to false unless you specify sourceDbClusterIdentifier and the source cluster is encrypted. In that case, encryption is inherited from the source cluster.

Using a different cloud?

Explore database guides for other cloud providers: