You can deploy AWS CDK stacks across multiple regions without needing to manage separate CDK projects for each region.

Let’s see this in action. Imagine you have a common infrastructure pattern – say, a VPC, a S3 bucket, and an EC2 instance – that you want to deploy in both us-east-1 and eu-west-2.

Here’s how you’d define that in your CDK app’s bin/my-app.ts:

#!/usr/bin/env node
import * as cdk from 'aws-cdk-lib';
import { MyAppStack } from '../lib/my-app-stack';

const app = new cdk.App();

// Deploy to us-east-1
new MyAppStack(app, 'MyAppStack-us-east-1', {
  env: {
    account: process.env.CDK_DEFAULT_ACCOUNT,
    region: 'us-east-1',
  },
  // Additional props specific to us-east-1 if needed
});

// Deploy to eu-west-2
new MyAppStack(app, 'MyAppStack-eu-west-2', {
  env: {
    account: process.env.CDK_DEFAULT_ACCOUNT,
    region: 'eu-west-2',
  },
  // Additional props specific to eu-west-2 if needed
});

And your lib/my-app-stack.ts would look like this:

import * as cdk from 'aws-cdk-lib';
import * as ec2 from 'aws-cdk-lib/aws-ec2';
import * as s3 from 'aws-cdk-lib/aws-s3';
import { Construct } from 'constructs';

export class MyAppStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    // Example: Create a VPC
    new ec2.Vpc(this, 'MyVpc', {
      maxAzs: 2, // Example value
    });

    // Example: Create an S3 bucket
    new s3.Bucket(this, 'MyBucket', {
      bucketName: `my-app-bucket-${cdk.Stack.of(this).region}-${cdk.Stack.of(this).account}`, // Unique name across regions/accounts
      versioned: true,
    });

    // Example: Create an EC2 instance (simplified)
    // In a real scenario, you'd configure instance type, AMI, etc.
    // For simplicity, we'll just show the construct.
    new ec2.Instance(this, 'MyInstance', {
      vpc: new ec2.Vpc.fromLookup(this, 'VpcLookup', {
        isDefault: true, // Assuming a default VPC exists for simplicity
      }),
      instanceType: ec2.InstanceType.of(ec2.InstanceClass.T3, ec2.InstanceSize.MICRO),
      machineImage: new ec2.AmazonLinuxImage(),
    });
  }
}

When you run cdk deploy, the CDK CLI intelligently handles deploying the same stack definition to each specified region. It generates separate CloudFormation templates for each region and provisions them independently.

The core problem this solves is avoiding duplicated infrastructure code for identical resources deployed in different geographical locations. Instead of copy-pasting entire CDK stacks, you define your stack logic once and then instantiate it multiple times with different env configurations. The env property is key here: it tells the CDK which AWS account and region a specific stack instance should be deployed to.

You can pass region-specific configurations via the props object when instantiating the stack. For instance, you might want to use different instance types or S3 bucket configurations based on the region. The cdk.Stack.of(this).region and cdk.Stack.of(this).account within your stack definition are invaluable for creating region-aware resource names or configurations.

To deploy to multiple regions simultaneously, you can use the --all flag with cdk deploy:

cdk deploy --all

This command will iterate through all stack instances defined in your bin directory and deploy each one to its specified env. If you only want to deploy specific stacks, you can list them:

cdk deploy MyAppStack-us-east-1 MyAppStack-eu-west-2

The env object in the StackProps is not just for region and account; it’s the primary mechanism by which the CDK determines the target deployment environment for a given stack instance. Without it, the CDK would default to the region and account configured in your AWS CLI/environment variables, and you’d only get one deployment.

When you define multiple stack instances with different env properties pointing to different regions, the CDK CLI generates a separate CloudFormation changeset for each. This means that if MyAppStack-us-east-1 fails, MyAppStack-eu-west-2 will likely still succeed (assuming no cross-region dependencies that fail).

A common pitfall is forgetting to make resource names unique across regions. For example, S3 bucket names must be globally unique. Using constructs like cdk.Stack.of(this).region and cdk.Stack.of(this).account in resource names is a robust way to ensure uniqueness.

This multi-region deployment pattern is fundamental for building resilient, performant, and compliant applications that serve users globally. It’s the same underlying mechanism that allows you to deploy different stacks to different environments (dev, staging, prod) within the same or different accounts and regions.

The next step after deploying to multiple regions is often orchestrating cross-region communication or data replication, which introduces concepts like SQS queues with cross-region delivery or DynamoDB Global Tables.

Want structured learning?

Take the full Cdk course →