Skip to content
v2.274.0

AWS Cloud Development Kit Library ​

Version 2.274.0

The AWS CDK construct library provides APIs to define your CDK application and add CDK constructs to the application.

Usage ​

Upgrade from CDK 1.x ​

When upgrading from CDK 1.x, remove all dependencies to individual CDK packages from your dependencies file and follow the rest of the sections.

Installation ​

To use this package, you need to declare this package and the constructs package as dependencies.

According to the kind of project you are developing:

For projects that are CDK libraries in NPM, declare them both under the devDependencies and peerDependencies sections. To make sure your library is compatible with the widest range of CDK versions: pick the minimum aws-cdk-lib version that your library requires; declare a range dependency with a caret on that version in peerDependencies, and declare a point version dependency on that version in devDependencies.

For example, let's say the minimum version your library needs is 2.38.0. Your package.json should look like this:

javascript
{
  "peerDependencies": {
    "aws-cdk-lib": "^2.38.0",
    "constructs": "^10.5.0"
  },
  "devDependencies": {
    /* Install the oldest version for testing so we don't accidentally use features from a newer version than we declare */
    "aws-cdk-lib": "2.38.0"
  }
}

For CDK apps, declare them under the dependencies section. Use a caret so you always get the latest version:

json
{
  "dependencies": {
    "aws-cdk-lib": "^2.38.0",
    "constructs": "^10.5.0"
  }
}

Use in your code ​

Classic import ​

You can use a classic import to get access to each service namespaces:

ts
import { Stack, App, aws_s3 as s3 } from 'aws-cdk-lib';

const app = new App();
const stack = new Stack(app, 'TestStack');

new s3.Bucket(stack, 'TestBucket');
python
from aws_cdk import Stack, App, aws_s3 as s3

app = App()
stack = Stack(app, "TestStack")

s3.Bucket(stack, "TestBucket")
java
import software.amazon.awscdk.Stack;
import software.amazon.awscdk.App;
import software.amazon.awscdk.services.s3.*;

App app = new App();
Stack stack = new Stack(app, "TestStack");

new Bucket(stack, "TestBucket");
csharp
using Amazon.CDK;
using Amazon.CDK.AWS.S3;

var app = new App();
var stack = new Stack(app, "TestStack");

new Bucket(stack, "TestBucket");
go
import "github.com/aws/aws-cdk-go/awscdk"

app := awscdk.NewApp()
stack := awscdk.NewStack(app, jsii.String("TestStack"))

awscdk.Aws_s3.NewBucket(stack, jsii.String("TestBucket"))

Barrel import ​

Alternatively, you can use "barrel" imports:

ts
import { App, Stack } from 'aws-cdk-lib';
import { Bucket } from 'aws-cdk-lib/aws-s3';

const app = new App();
const stack = new Stack(app, 'TestStack');

new Bucket(stack, 'TestBucket');
python
from aws_cdk import App, Stack
from aws_cdk.aws_s3 import Bucket

app = App()
stack = Stack(app, "TestStack")

Bucket(stack, "TestBucket")
java
import software.amazon.awscdk.App;
import software.amazon.awscdk.Stack;
import software.amazon.awscdk.services.s3.Bucket;

App app = new App();
Stack stack = new Stack(app, "TestStack");

new Bucket(stack, "TestBucket");
csharp
using Amazon.CDK;
using Amazon.CDK.AWS.S3;

var app = new App();
var stack = new Stack(app, "TestStack");

new Bucket(stack, "TestBucket");
go
import "github.com/aws/aws-cdk-go/awscdk"
import "github.com/aws/aws-cdk-go/awscdk"

app := awscdk.NewApp()
stack := awscdk.NewStack(app, jsii.String("TestStack"))

awscdk.NewBucket(stack, jsii.String("TestBucket"))

Stacks and Stages ​

A Stack is the smallest physical unit of deployment, and maps directly onto a CloudFormation Stack. You define a Stack by defining a subclass of Stack -- let's call it MyStack -- and instantiating the constructs that make up your application in MyStack's constructor. You then instantiate this stack one or more times to define different instances of your application. For example, you can instantiate it once using few and cheap EC2 instances for testing, and once again using more and bigger EC2 instances for production.

When your application grows, you may decide that it makes more sense to split it out across multiple Stack classes. This can happen for a number of reasons:

  • You could be starting to reach the maximum number of resources allowed in a single stack (this is currently 500).
  • You could decide you want to separate out stateful resources and stateless resources into separate stacks, so that it becomes easy to tear down and recreate the stacks that don't have stateful resources.
  • There could be a single stack with resources (like a VPC) that are shared between multiple instances of other stacks containing your applications.

As soon as your conceptual application starts to encompass multiple stacks, it is convenient to wrap them in another construct that represents your logical application. You can then treat that new unit the same way you used to be able to treat a single stack: by instantiating it multiple times for different instances of your application.

You can define a custom subclass of Stage, holding one or more Stacks, to represent a single logical instance of your application.

As a final note: Stacks are not a unit of reuse. They describe physical deployment layouts, and as such are best left to application builders to organize their deployments with. If you want to vend a reusable construct, define it as a subclasses of Construct: the consumers of your construct will decide where to place it in their own stacks.

Stack Synthesizers ​

Each Stack has a synthesizer, an object that determines how and where the Stack should be synthesized and deployed. The synthesizer controls aspects like:

  • How does the stack reference assets? (Either through CloudFormation parameters the CLI supplies, or because the Stack knows a predefined location where assets will be uploaded).
  • What roles are used to deploy the stack? These can be bootstrapped roles, roles created in some other way, or just the CLI's current credentials.

The following synthesizers are available:

  • DefaultStackSynthesizer: recommended. Uses predefined asset locations and roles created by the modern bootstrap template. Access control is done by controlling who can assume the deploy role. This is the default stack synthesizer in CDKv2.
  • LegacyStackSynthesizer: Uses CloudFormation parameters to communicate asset locations, and the CLI's current permissions to deploy stacks. This is the default stack synthesizer in CDKv1.
  • CliCredentialsStackSynthesizer: Uses predefined asset locations, and the CLI's current permissions.

Each of these synthesizers takes configuration arguments. To configure a stack with a synthesizer, pass it as one of its properties:

ts
new MyStack(app, 'MyStack', {
  synthesizer: new DefaultStackSynthesizer({
    fileAssetsBucketName: 'amzn-s3-demo-bucket',
  }),
});
python
MyStack(app, "MyStack",
    synthesizer=DefaultStackSynthesizer(
        file_assets_bucket_name="amzn-s3-demo-bucket"
    )
)
java
MyStack.Builder.create(app, "MyStack")
        .synthesizer(DefaultStackSynthesizer.Builder.create()
                .fileAssetsBucketName("amzn-s3-demo-bucket")
                .build())
        .build();
csharp
new MyStack(app, "MyStack", new StackProps {
    Synthesizer = new DefaultStackSynthesizer(new DefaultStackSynthesizerProps {
        FileAssetsBucketName = "amzn-s3-demo-bucket"
    })
});
go
NewMyStack(app, jsii.String("MyStack"), &StackProps{
	Synthesizer: awscdk.NewDefaultStackSynthesizer(&DefaultStackSynthesizerProps{
		FileAssetsBucketName: jsii.String("amzn-s3-demo-bucket"),
	}),
})

For more information on bootstrapping accounts and customizing synthesis, see Bootstrapping in the CDK Developer Guide.

STS Role Options ​

You can configure STS options that instruct the CDK CLI on which configuration should it use when assuming the various roles that are involved in a deployment operation.

Refer to the bootstrapping guide for further context.

These options are available via the DefaultStackSynthesizer properties:

ts
class MyStack extends Stack {
  constructor(scope: Construct, id: string, props: StackProps) {
    super(scope, id, {
      ...props,
      synthesizer: new DefaultStackSynthesizer({
        deployRoleExternalId: '',
        deployRoleAdditionalOptions: {
          // https://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRole.html#API_AssumeRole_RequestParameters
        },
        fileAssetPublishingExternalId: '',
        fileAssetPublishingRoleAdditionalOptions: {
          // https://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRole.html#API_AssumeRole_RequestParameters
        },
        imageAssetPublishingExternalId: '',
        imageAssetPublishingRoleAdditionalOptions: {
          // https://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRole.html#API_AssumeRole_RequestParameters
        },
        lookupRoleExternalId: '',
        lookupRoleAdditionalOptions: {
          // https://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRole.html#API_AssumeRole_RequestParameters
        },
      })
    });
  }
}
python
class MyStack(Stack):
    def __init__(self, scope, id, *, description=None, env=None, stackName=None, tags=None, notificationArns=None, synthesizer=None, terminationProtection=None, analyticsReporting=None, crossRegionReferences=None, permissionsBoundary=None, suppressTemplateIndentation=None, propertyInjectors=None):
        super().__init__(scope, id,
            (SpreadAssignment ...props
              description=description, env=env, stackName=stackName, tags=tags, notificationArns=notificationArns, synthesizer=synthesizer, terminationProtection=terminationProtection, analyticsReporting=analyticsReporting, crossRegionReferences=crossRegionReferences, permissionsBoundary=permissionsBoundary, suppressTemplateIndentation=suppressTemplateIndentation, propertyInjectors=propertyInjectors),
            synthesizer=DefaultStackSynthesizer(
                deploy_role_external_id="",
                deploy_role_additional_options={},
                file_asset_publishing_external_id="",
                file_asset_publishing_role_additional_options={},
                image_asset_publishing_external_id="",
                image_asset_publishing_role_additional_options={},
                lookup_role_external_id="",
                lookup_role_additional_options={}
            )
        )
java
public class MyStack extends Stack {
    public MyStack(Construct scope, String id, StackProps props) {
        super(scope, id, StackProps.builder()
                (SpreadAssignment ...props
                  props)
                .synthesizer(DefaultStackSynthesizer.Builder.create()
                        .deployRoleExternalId("")
                        .deployRoleAdditionalOptions(Map.of())
                        .fileAssetPublishingExternalId("")
                        .fileAssetPublishingRoleAdditionalOptions(Map.of())
                        .imageAssetPublishingExternalId("")
                        .imageAssetPublishingRoleAdditionalOptions(Map.of())
                        .lookupRoleExternalId("")
                        .lookupRoleAdditionalOptions(Map.of())
                        .build())
                .build());
    }
}
csharp
class MyStack : Stack
{
    public MyStack(Construct scope, string id, StackProps props) : base(scope, id, new StackProps {
        (SpreadAssignment ...props
          props),
        Synthesizer = new DefaultStackSynthesizer(new DefaultStackSynthesizerProps {
            DeployRoleExternalId = "",
            DeployRoleAdditionalOptions = new Dictionary<string, object> { },
            FileAssetPublishingExternalId = "",
            FileAssetPublishingRoleAdditionalOptions = new Dictionary<string, object> { },
            ImageAssetPublishingExternalId = "",
            ImageAssetPublishingRoleAdditionalOptions = new Dictionary<string, object> { },
            LookupRoleExternalId = "",
            LookupRoleAdditionalOptions = new Dictionary<string, object> { }
        })
    })
    {
    }
}
go
type myStack struct {
	Stack
}

func newMyStack(scope Construct, id *string, props StackProps) *myStack {
	this := &myStack{}
	newStack_Override(this, scope, id, &StackProps{
		(SpreadAssignment ...props
				Props),
		Synthesizer: awscdk.NewDefaultStackSynthesizer(&DefaultStackSynthesizerProps{
			DeployRoleExternalId: jsii.String(""),
			DeployRoleAdditionalOptions: map[string]interface{}{
			},
			FileAssetPublishingExternalId: jsii.String(""),
			FileAssetPublishingRoleAdditionalOptions: map[string]interface{}{
			},
			ImageAssetPublishingExternalId: jsii.String(""),
			ImageAssetPublishingRoleAdditionalOptions: map[string]interface{}{
			},
			LookupRoleExternalId: jsii.String(""),
			LookupRoleAdditionalOptions: map[string]interface{}{
			},
		}),
	})
	return this
}

Note that the *additionalOptions property does not allow passing ExternalId or RoleArn, as these options have dedicated properties that configure them.

Session Tags ​

STS session tags are used to implement Attribute-Based Access Control (ABAC).

See IAM tutorial: Define permissions to access AWS resources based on tags.

You can pass session tags for each role created during bootstrap via the *additionalOptions property:

ts
class MyStack extends Stack {
  constructor(parent: Construct, id: string, props: StackProps) {
    super(parent, id, {
      ...props,
      synthesizer: new DefaultStackSynthesizer({
        deployRoleAdditionalOptions: {
          Tags: [{ Key: 'Department', Value: 'Engineering' }]
        },
        fileAssetPublishingRoleAdditionalOptions: {
          Tags: [{ Key: 'Department', Value: 'Engineering' }]
        },
        imageAssetPublishingRoleAdditionalOptions: {
          Tags: [{ Key: 'Department', Value: 'Engineering' }]
        },
        lookupRoleAdditionalOptions: {
          Tags: [{ Key: 'Department', Value: 'Engineering' }]
        },
      })
    });
  }
}
python
class MyStack(Stack):
    def __init__(self, parent, id, *, description=None, env=None, stackName=None, tags=None, notificationArns=None, synthesizer=None, terminationProtection=None, analyticsReporting=None, crossRegionReferences=None, permissionsBoundary=None, suppressTemplateIndentation=None, propertyInjectors=None):
        super().__init__(parent, id,
            (SpreadAssignment ...props
              description=description, env=env, stackName=stackName, tags=tags, notificationArns=notificationArns, synthesizer=synthesizer, terminationProtection=terminationProtection, analyticsReporting=analyticsReporting, crossRegionReferences=crossRegionReferences, permissionsBoundary=permissionsBoundary, suppressTemplateIndentation=suppressTemplateIndentation, propertyInjectors=propertyInjectors),
            synthesizer=DefaultStackSynthesizer(
                deploy_role_additional_options={
                    "Tags": [{"Key": "Department", "Value": "Engineering"}]
                },
                file_asset_publishing_role_additional_options={
                    "Tags": [{"Key": "Department", "Value": "Engineering"}]
                },
                image_asset_publishing_role_additional_options={
                    "Tags": [{"Key": "Department", "Value": "Engineering"}]
                },
                lookup_role_additional_options={
                    "Tags": [{"Key": "Department", "Value": "Engineering"}]
                }
            )
        )
java
public class MyStack extends Stack {
    public MyStack(Construct parent, String id, StackProps props) {
        super(parent, id, StackProps.builder()
                (SpreadAssignment ...props
                  props)
                .synthesizer(DefaultStackSynthesizer.Builder.create()
                        .deployRoleAdditionalOptions(Map.of(
                                "Tags", List.of(Map.of("Key", "Department", "Value", "Engineering"))))
                        .fileAssetPublishingRoleAdditionalOptions(Map.of(
                                "Tags", List.of(Map.of("Key", "Department", "Value", "Engineering"))))
                        .imageAssetPublishingRoleAdditionalOptions(Map.of(
                                "Tags", List.of(Map.of("Key", "Department", "Value", "Engineering"))))
                        .lookupRoleAdditionalOptions(Map.of(
                                "Tags", List.of(Map.of("Key", "Department", "Value", "Engineering"))))
                        .build())
                .build());
    }
}
csharp
class MyStack : Stack
{
    public MyStack(Construct parent, string id, StackProps props) : base(parent, id, new StackProps {
        (SpreadAssignment ...props
          props),
        Synthesizer = new DefaultStackSynthesizer(new DefaultStackSynthesizerProps {
            DeployRoleAdditionalOptions = new Dictionary<string, object> {
                { "Tags", new [] { new Dictionary<string, string> { { "Key", "Department" }, { "Value", "Engineering" } } } }
            },
            FileAssetPublishingRoleAdditionalOptions = new Dictionary<string, object> {
                { "Tags", new [] { new Dictionary<string, string> { { "Key", "Department" }, { "Value", "Engineering" } } } }
            },
            ImageAssetPublishingRoleAdditionalOptions = new Dictionary<string, object> {
                { "Tags", new [] { new Dictionary<string, string> { { "Key", "Department" }, { "Value", "Engineering" } } } }
            },
            LookupRoleAdditionalOptions = new Dictionary<string, object> {
                { "Tags", new [] { new Dictionary<string, string> { { "Key", "Department" }, { "Value", "Engineering" } } } }
            }
        })
    })
    {
    }
}
go
type myStack struct {
	Stack
}

func newMyStack(parent Construct, id *string, props StackProps) *myStack {
	this := &myStack{}
	newStack_Override(this, parent, id, &StackProps{
		(SpreadAssignment ...props
				Props),
		Synthesizer: awscdk.NewDefaultStackSynthesizer(&DefaultStackSynthesizerProps{
			DeployRoleAdditionalOptions: map[string]interface{}{
				"Tags": []interface{}{
					map[string]*string{
						"Key": jsii.String("Department"),
						"Value": jsii.String("Engineering"),
					},
				},
			},
			FileAssetPublishingRoleAdditionalOptions: map[string]interface{}{
				"Tags": []interface{}{
					map[string]*string{
						"Key": jsii.String("Department"),
						"Value": jsii.String("Engineering"),
					},
				},
			},
			ImageAssetPublishingRoleAdditionalOptions: map[string]interface{}{
				"Tags": []interface{}{
					map[string]*string{
						"Key": jsii.String("Department"),
						"Value": jsii.String("Engineering"),
					},
				},
			},
			LookupRoleAdditionalOptions: map[string]interface{}{
				"Tags": []interface{}{
					map[string]*string{
						"Key": jsii.String("Department"),
						"Value": jsii.String("Engineering"),
					},
				},
			},
		}),
	})
	return this
}

This will cause the CDK CLI to include session tags when assuming each of these roles during deployment. Note that the trust policy of the role must contain permissions for the sts:TagSession action.

Refer to the IAM user guide on session tags.

  • If you are using a custom bootstrap template, make sure the template includes these permissions.
  • If you are using the default bootstrap template from a CDK version lower than XXXX, you will need to rebootstrap your enviroment (once).

Nested Stacks ​

Nested stacks are stacks created as part of other stacks. You create a nested stack within another stack by using the NestedStack construct.

As your infrastructure grows, common patterns can emerge in which you declare the same components in multiple templates. You can separate out these common components and create dedicated templates for them. Then use the resource in your template to reference other templates, creating nested stacks.

For example, assume that you have a load balancer configuration that you use for most of your stacks. Instead of copying and pasting the same configurations into your templates, you can create a dedicated template for the load balancer. Then, you just use the resource to reference that template from within other templates.

The following example will define a single top-level stack that contains two nested stacks: each one with a single Amazon S3 bucket:

ts
class MyNestedStack extends cfn.NestedStack {
  constructor(scope: Construct, id: string, props?: cfn.NestedStackProps) {
    super(scope, id, props);

    new s3.Bucket(this, 'NestedBucket');
  }
}

class MyParentStack extends Stack {
  constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, props);

    new MyNestedStack(this, 'Nested1');
    new MyNestedStack(this, 'Nested2');
  }
}
python
class MyNestedStack(cfn.NestedStack):
    def __init__(self, scope, id, *, parameters=None, timeout=None, notifications=None):
        super().__init__(scope, id, parameters=parameters, timeout=timeout, notifications=notifications)

        s3.Bucket(self, "NestedBucket")

class MyParentStack(Stack):
    def __init__(self, scope, id, *, description=None, env=None, stackName=None, tags=None, notificationArns=None, synthesizer=None, terminationProtection=None, analyticsReporting=None, crossRegionReferences=None, permissionsBoundary=None, suppressTemplateIndentation=None, propertyInjectors=None):
        super().__init__(scope, id, description=description, env=env, stackName=stackName, tags=tags, notificationArns=notificationArns, synthesizer=synthesizer, terminationProtection=terminationProtection, analyticsReporting=analyticsReporting, crossRegionReferences=crossRegionReferences, permissionsBoundary=permissionsBoundary, suppressTemplateIndentation=suppressTemplateIndentation, propertyInjectors=propertyInjectors)

        MyNestedStack(self, "Nested1")
        MyNestedStack(self, "Nested2")
java
public class MyNestedStack extends NestedStack {
    public MyNestedStack(Construct scope, String id) {
        this(scope, id, null);
    }

    public MyNestedStack(Construct scope, String id, NestedStackProps props) {
        super(scope, id, props);

        new Bucket(this, "NestedBucket");
    }
}

public class MyParentStack extends Stack {
    public MyParentStack(Construct scope, String id) {
        this(scope, id, null);
    }

    public MyParentStack(Construct scope, String id, StackProps props) {
        super(scope, id, props);

        new MyNestedStack(this, "Nested1");
        new MyNestedStack(this, "Nested2");
    }
}
csharp
class MyNestedStack : NestedStack
{
    public MyNestedStack(Construct scope, string id, NestedStackProps? props=null) : base(scope, id, props)
    {

        new Bucket(this, "NestedBucket");
    }
}

class MyParentStack : Stack
{
    public MyParentStack(Construct scope, string id, StackProps? props=null) : base(scope, id, props)
    {

        new MyNestedStack(this, "Nested1");
        new MyNestedStack(this, "Nested2");
    }
}
go
type myNestedStack struct {
	NestedStack
}

func newMyNestedStack(scope Construct, id *string, props NestedStackProps) *myNestedStack {
	this := &myNestedStack{}
	cfn.NewNestedStack_Override(this, scope, id, props)

	s3.NewBucket(this, jsii.String("NestedBucket"))
	return this
}

type myParentStack struct {
	Stack
}

func newMyParentStack(scope Construct, id *string, props StackProps) *myParentStack {
	this := &myParentStack{}
	newStack_Override(this, scope, id, props)

	NewMyNestedStack(this, jsii.String("Nested1"))
	NewMyNestedStack(this, jsii.String("Nested2"))
	return this
}

Resources references across nested/parent boundaries (even with multiple levels of nesting) will be wired by the AWS CDK through CloudFormation parameters and outputs. When a resource from a parent stack is referenced by a nested stack, a CloudFormation parameter will automatically be added to the nested stack and assigned from the parent; when a resource from a nested stack is referenced by a parent stack, a CloudFormation output will be automatically be added to the nested stack and referenced using Fn::GetAtt "Outputs.Xxx" from the parent.

Nested stacks also support the use of Docker image and file assets.

Accessing resources in a different stack ​

You can pass resource references between stacks freely, including across regions and accounts. The CDK automatically wires the underlying CloudFormation mechanism for you.

ts
const prod = { account: '123456789012', region: 'us-east-1' };

const stack1 = new StackThatProvidesABucket(app, 'Stack1' , { env: prod });

// stack2 will take a property { bucket: IBucket }
const stack2 = new StackThatExpectsABucket(app, 'Stack2', {
  bucket: stack1.bucket,
  env: prod
});
python
prod = {"account": "123456789012", "region": "us-east-1"}

stack1 = StackThatProvidesABucket(app, "Stack1", env=prod)

# stack2 will take a property { bucket: IBucket }
stack2 = StackThatExpectsABucket(app, "Stack2",
    bucket=stack1.bucket,
    env=prod
)
java
Map<String, String> prod = Map.of("account", "123456789012", "region", "us-east-1");

StackThatProvidesABucket stack1 = StackThatProvidesABucket.Builder.create(app, "Stack1").env(prod).build();

// stack2 will take a property { bucket: IBucket }
StackThatExpectsABucket stack2 = new StackThatExpectsABucket(app, "Stack2", new StackThatExpectsABucketProps()
        .bucket(stack1.getBucket())
        .env(prod)
        );
csharp
IDictionary<string, string> prod = new Dictionary<string, string> { { "account", "123456789012" }, { "region", "us-east-1" } };

var stack1 = new StackThatProvidesABucket(app, "Stack1", new StackProps { Env = prod });

// stack2 will take a property { bucket: IBucket }
var stack2 = new StackThatExpectsABucket(app, "Stack2", new StackThatExpectsABucketProps {
    Bucket = stack1.Bucket,
    Env = prod
});
go
prod := map[string]*string{
	"account": jsii.String("123456789012"),
	"region": jsii.String("us-east-1"),
}

stack1 := NewStackThatProvidesABucket(app, jsii.String("Stack1"), &StackProps{
	Env: prod,
})

// stack2 will take a property { bucket: IBucket }
stack2 := NewStackThatExpectsABucket(app, jsii.String("Stack2"), &stackThatExpectsABucketProps{
	bucket: stack1.bucket,
	env: prod,
})

This also works across regions. For example, you can create a CloudFront distribution in us-east-2 that references an ACM certificate in us-east-1:

ts
const stack1 = new Stack(app, 'Stack1', {
  env: {
    region: 'us-east-1',
  },
});
const cert = new acm.Certificate(stack1, 'Cert', {
  domainName: '*.example.com',
  validation: acm.CertificateValidation.fromDns(route53.PublicHostedZone.fromHostedZoneId(stack1, 'Zone', 'Z0329774B51CGXTDQV3X')),
});

const stack2 = new Stack(app, 'Stack2', {
  env: {
    region: 'us-east-2',
  },
});
new cloudfront.Distribution(stack2, 'Distribution', {
  defaultBehavior: {
    origin: new origins.HttpOrigin('example.com'),
  },
  domainNames: ['dev.example.com'],
  certificate: cert,
});
python
from aws_cdk import Environment, Environment
stack1 = Stack(app, "Stack1",
    env=Environment(
        region="us-east-1"
    )
)
cert = acm.Certificate(stack1, "Cert",
    domain_name="*.example.com",
    validation=acm.CertificateValidation.from_dns(route53.PublicHostedZone.from_hosted_zone_id(stack1, "Zone", "Z0329774B51CGXTDQV3X"))
)

stack2 = Stack(app, "Stack2",
    env=Environment(
        region="us-east-2"
    )
)
cloudfront.Distribution(stack2, "Distribution",
    default_behavior=cloudfront.BehaviorOptions(
        origin=origins.HttpOrigin("example.com")
    ),
    domain_names=["dev.example.com"],
    certificate=cert
)
java
Stack stack1 = Stack.Builder.create(app, "Stack1")
        .env(Environment.builder()
                .region("us-east-1")
                .build())
        .build();
Certificate cert = Certificate.Builder.create(stack1, "Cert")
        .domainName("*.example.com")
        .validation(CertificateValidation.fromDns(PublicHostedZone.fromHostedZoneId(stack1, "Zone", "Z0329774B51CGXTDQV3X")))
        .build();

Stack stack2 = Stack.Builder.create(app, "Stack2")
        .env(Environment.builder()
                .region("us-east-2")
                .build())
        .build();
Distribution.Builder.create(stack2, "Distribution")
        .defaultBehavior(BehaviorOptions.builder()
                .origin(new HttpOrigin("example.com"))
                .build())
        .domainNames(List.of("dev.example.com"))
        .certificate(cert)
        .build();
csharp
var stack1 = new Stack(app, "Stack1", new StackProps {
    Env = new Environment {
        Region = "us-east-1"
    }
});
var cert = new Certificate(stack1, "Cert", new CertificateProps {
    DomainName = "*.example.com",
    Validation = CertificateValidation.FromDns(PublicHostedZone.FromHostedZoneId(stack1, "Zone", "Z0329774B51CGXTDQV3X"))
});

var stack2 = new Stack(app, "Stack2", new StackProps {
    Env = new Environment {
        Region = "us-east-2"
    }
});
new Distribution(stack2, "Distribution", new DistributionProps {
    DefaultBehavior = new BehaviorOptions {
        Origin = new HttpOrigin("example.com")
    },
    DomainNames = new [] { "dev.example.com" },
    Certificate = cert
});
go
stack1 := awscdk.Newstack(app, jsii.String("Stack1"), &StackProps{
	Env: &Environment{
		Region: jsii.String("us-east-1"),
	},
})
cert := acm.NewCertificate(stack1, jsii.String("Cert"), &CertificateProps{
	DomainName: jsii.String("*.example.com"),
	Validation: acm.CertificateValidation_FromDns(route53.PublicHostedZone_FromHostedZoneId(stack1, jsii.String("Zone"), jsii.String("Z0329774B51CGXTDQV3X"))),
})

stack2 := awscdk.Newstack(app, jsii.String("Stack2"), &StackProps{
	Env: &Environment{
		Region: jsii.String("us-east-2"),
	},
})
cloudfront.NewDistribution(stack2, jsii.String("Distribution"), &DistributionProps{
	DefaultBehavior: &BehaviorOptions{
		Origin: origins.NewHttpOrigin(jsii.String("example.com")),
	},
	DomainNames: []*string{
		jsii.String("dev.example.com"),
	},
	Certificate: cert,
})

Reference strength ​

Every cross-stack reference has a strength that determines the CloudFormation mechanism used to pass the value and the coupling it creates between stacks. There are three strengths:

Strong (default) — the producing stack cannot be deleted while any consumer exists. This is enforced by CloudFormation itself.

Weak — uses Fn::GetStackOutput to read an output directly from the producing stack. No coupling is created: the producing stack or resource can be deleted independently. This means consuming stacks may temporarily reference a nonexistent resource until they are updated as well.

Both — a transitional state used when migrating from strong to weak. The producer keeps the strong-side artifacts while the consumer switches to Fn::GetStackOutput. Once all consumers have been deployed with the weak mechanism, the strong-side artifacts can be safely removed.

The exact CloudFormation realization depends on the strength and whether the reference crosses region or account boundaries:

RowStrong (default)BothWeak
Same account and regionGenerates a Fn::ImportValue referenceGenerates a Fn::GetStackOutput reference AND an Export, but not the Fn::ImportValueGenerates a Fn::GetStackOutput reference
Same account, cross-regionGenerates a pair of ExportWriter/ExportReaderGenerates a Fn::GetStackOutput reference AND an ExportWriter, but not the ExportReaderGenerates a Fn::GetStackOutput reference
Cross-accountNot possible. Falls back to weak.Generates a Fn::GetStackOutput reference + cross-account roleGenerates a Fn::GetStackOutput reference + cross-account role

NOTE

Strong cross-region references rely on Custom Resources, which are restricted to a CloudFormation response body size of 4096 bytes. To prevent deployment errors, limit the use of nested stacks and minimize stack name length.

The deadly embrace ​

Strong references create a deadly embrace: a circular dependency between stacks that prevents any of them from being updated or deleted. This happens because CloudFormation Exports cannot be removed while any other stack imports them, and the producing stack cannot be updated to remove the Export as long as the consuming stack still has a Fn::ImportValue referencing it.

In practice, you hit the deadly embrace when you try to remove a resource that is referenced by another stack. CloudFormation will reject the update with an error like:

text
Export Stack1:ExportsOutputFnGetAtt-****** cannot be deleted as it is in use by Stack2

The solution is to first weaken the reference (switching the consumer away from Fn::ImportValue), deploy, and then remove the resource. The sections below explain how to do this.

Controlling reference strength ​

There are three ways to control the strength of cross-stack references, each operating at a different scope:

App-wide: context key ​

Set @aws-cdk/core:defaultCrossStackReferences in cdk.json to change the default for all references in the app:

json
{
  "context": {
    "@aws-cdk/core:defaultCrossStackReferences": "weak"
  }
}

You can also set this on a specific scope (stack, construct) using CrossStackReferences.of(scope).consume(strength):

ts
declare const consumer: Stack;
// All references consumed by this stack will be weak
CrossStackReferences.of(consumer).consume(ReferenceStrength.WEAK);
python
# consumer: Stack

# All references consumed by this stack will be weak
CrossStackReferences.of(consumer).consume(ReferenceStrength.WEAK)
java
Stack consumer;

// All references consumed by this stack will be weak
CrossStackReferences.of(consumer).consume(ReferenceStrength.WEAK);
csharp
Stack consumer;

// All references consumed by this stack will be weak
CrossStackReferences.Of(consumer).Consume(ReferenceStrength.WEAK);
go
var consumer Stack

// All references consumed by this stack will be weak
awscdk.CrossStackReferences_Of(consumer).Consume(awscdk.ReferenceStrength_WEAK)

Per-resource: CrossStackReferences.of(resource).produce(strength) ​

Override the strength for all references pointing at a specific resource:

ts
declare const producer: Stack;
declare const consumer: Stack;

const bucket = new s3.Bucket(producer, 'SharedBucket');
CrossStackReferences.of(bucket).produce(ReferenceStrength.WEAK);

// This reference will use Fn::GetStackOutput regardless of the global setting
new CfnOutput(consumer, 'BucketName', { value: bucket.bucketName });
python
# producer: Stack
# consumer: Stack


bucket = s3.Bucket(producer, "SharedBucket")
CrossStackReferences.of(bucket).produce(ReferenceStrength.WEAK)

# This reference will use Fn::GetStackOutput regardless of the global setting
CfnOutput(consumer, "BucketName", value=bucket.bucket_name)
java
Stack producer;
Stack consumer;


Bucket bucket = new Bucket(producer, "SharedBucket");
CrossStackReferences.of(bucket).produce(ReferenceStrength.WEAK);

// This reference will use Fn::GetStackOutput regardless of the global setting
// This reference will use Fn::GetStackOutput regardless of the global setting
CfnOutput.Builder.create(consumer, "BucketName").value(bucket.getBucketName()).build();
csharp
Stack producer;
Stack consumer;


var bucket = new Bucket(producer, "SharedBucket");
CrossStackReferences.Of(bucket).Produce(ReferenceStrength.WEAK);

// This reference will use Fn::GetStackOutput regardless of the global setting
// This reference will use Fn::GetStackOutput regardless of the global setting
new CfnOutput(consumer, "BucketName", new CfnOutputProps { Value = bucket.BucketName });
go
var producer Stack
var consumer Stack


bucket := s3.NewBucket(producer, jsii.String("SharedBucket"))
awscdk.CrossStackReferences_Of(bucket).Produce(awscdk.ReferenceStrength_WEAK)

// This reference will use Fn::GetStackOutput regardless of the global setting
// This reference will use Fn::GetStackOutput regardless of the global setting
awscdk.NewCfnOutput(consumer, jsii.String("BucketName"), &CfnOutputProps{
	Value: bucket.bucketName,
})

Other resources in the same stack continue to use the global default.

Per-usage: Stack.consumeReference() ​

Override the strength of a single reference usage without affecting other usages of the same resource:

ts
declare const topic: sns.Topic;

const consumer = new Stack(app, 'Consumer', {
  env: { account: '123456789012', region: 'us-east-1' },
});
new sns.Subscription(consumer, 'Subscription', {
  topic: sns.Topic.fromTopicArn(consumer, 'Topic',
    Stack.consumeReference(topic.topicArn, ReferenceStrength.WEAK)),
  endpoint: 'https://example.com/webhook',
  protocol: sns.SubscriptionProtocol.HTTPS,
});
python
from aws_cdk import Environment
# topic: sns.Topic


consumer = Stack(app, "Consumer",
    env=Environment(account="123456789012", region="us-east-1")
)
sns.Subscription(consumer, "Subscription",
    topic=sns.Topic.from_topic_arn(consumer, "Topic",
        Stack.consume_reference(topic.topic_arn, ReferenceStrength.WEAK)),
    endpoint="https://example.com/webhook",
    protocol=sns.SubscriptionProtocol.HTTPS
)
java
Topic topic;


Stack consumer = Stack.Builder.create(app, "Consumer")
        .env(Environment.builder().account("123456789012").region("us-east-1").build())
        .build();
Subscription.Builder.create(consumer, "Subscription")
        .topic(Topic.fromTopicArn(consumer, "Topic", Stack.consumeReference(topic.getTopicArn(), ReferenceStrength.WEAK)))
        .endpoint("https://example.com/webhook")
        .protocol(SubscriptionProtocol.HTTPS)
        .build();
csharp
Topic topic;


var consumer = new Stack(app, "Consumer", new StackProps {
    Env = new Environment { Account = "123456789012", Region = "us-east-1" }
});
new Subscription(consumer, "Subscription", new SubscriptionProps {
    Topic = Topic.FromTopicArn(consumer, "Topic", Stack.ConsumeReference(topic.TopicArn, ReferenceStrength.WEAK)),
    Endpoint = "https://example.com/webhook",
    Protocol = SubscriptionProtocol.HTTPS
});
go
var topic Topic


consumer := awscdk.Newstack(app, jsii.String("Consumer"), &StackProps{
	Env: &Environment{
		Account: jsii.String("123456789012"),
		Region: jsii.String("us-east-1"),
	},
})
sns.NewSubscription(consumer, jsii.String("Subscription"), &SubscriptionProps{
	Topic: sns.Topic_FromTopicArn(consumer, jsii.String("Topic"), awscdk.*stack_ConsumeReference(topic.topicArn, awscdk.ReferenceStrength_WEAK)),
	Endpoint: jsii.String("https://example.com/webhook"),
	Protocol: sns.SubscriptionProtocol_HTTPS,
})

The consumeListReference method is the equivalent for string list references.

Resolving the deadly embrace ​

To remove a resource that has strong cross-stack references, you must weaken the references before removing the resource. There are two approaches depending on whether you want to weaken all references to the resource or just a specific one.

Weakening all references to a resource ​

Use CrossStackReferences.of(resource).produce(...) to weaken every reference pointing at the resource. This requires two deployments before you can remove it:

DEPLOYMENT 1: switch to BOTH (keeps the strong-side artifacts while consumers switch to the weak mechanism)

ts
declare const bucket: s3.Bucket;
CrossStackReferences.of(bucket).produce(ReferenceStrength.BOTH);
python
# bucket: s3.Bucket

CrossStackReferences.of(bucket).produce(ReferenceStrength.BOTH)
java
Bucket bucket;

CrossStackReferences.of(bucket).produce(ReferenceStrength.BOTH);
csharp
Bucket bucket;

CrossStackReferences.Of(bucket).Produce(ReferenceStrength.BOTH);
go
var bucket Bucket

awscdk.CrossStackReferences_Of(bucket).Produce(awscdk.ReferenceStrength_BOTH)

DEPLOYMENT 2: switch to WEAK (removes the strong-side artifacts now that no consumer depends on them)

ts
declare const bucket: s3.Bucket;
CrossStackReferences.of(bucket).produce(ReferenceStrength.WEAK);
python
# bucket: s3.Bucket

CrossStackReferences.of(bucket).produce(ReferenceStrength.WEAK)
java
Bucket bucket;

CrossStackReferences.of(bucket).produce(ReferenceStrength.WEAK);
csharp
Bucket bucket;

CrossStackReferences.Of(bucket).Produce(ReferenceStrength.WEAK);
go
var bucket Bucket

awscdk.CrossStackReferences_Of(bucket).Produce(awscdk.ReferenceStrength_WEAK)

DEPLOYMENT 3: remove the bucket from stack1 and any references from stack2.

Weakening a single reference ​

Use Stack.consumeReference() to weaken just one specific usage. This is useful when a resource is referenced from multiple stacks, and you only want to decouple one of them. The same two-deployment migration applies:

DEPLOYMENT 1: wrap the reference with consumeReference (defaults to BOTH)

ts
declare const bucket: s3.Bucket;
declare const consumer: Stack;

// Previously: bucket.bucketArn was used directly
new CfnOutput(consumer, 'BucketArn', {
  value: Stack.consumeReference(bucket.bucketArn),
});
python
# bucket: s3.Bucket
# consumer: Stack


# Previously: bucket.bucketArn was used directly
CfnOutput(consumer, "BucketArn",
    value=Stack.consume_reference(bucket.bucket_arn)
)
java
Bucket bucket;
Stack consumer;


// Previously: bucket.bucketArn was used directly
// Previously: bucket.bucketArn was used directly
CfnOutput.Builder.create(consumer, "BucketArn")
        .value(Stack.consumeReference(bucket.getBucketArn()))
        .build();
csharp
Bucket bucket;
Stack consumer;


// Previously: bucket.bucketArn was used directly
// Previously: bucket.bucketArn was used directly
new CfnOutput(consumer, "BucketArn", new CfnOutputProps {
    Value = Stack.ConsumeReference(bucket.BucketArn)
});
go
var bucket Bucket
var consumer Stack


// Previously: bucket.bucketArn was used directly
// Previously: bucket.bucketArn was used directly
awscdk.NewCfnOutput(consumer, jsii.String("BucketArn"), &CfnOutputProps{
	Value: awscdk.*stack_ConsumeReference(bucket.bucketArn),
})

DEPLOYMENT 2: switch to WEAK

ts
declare const bucket: s3.Bucket;
declare const consumer: Stack;

new CfnOutput(consumer, 'BucketArn', {
  value: Stack.consumeReference(bucket.bucketArn, ReferenceStrength.WEAK),
});
python
# bucket: s3.Bucket
# consumer: Stack


CfnOutput(consumer, "BucketArn",
    value=Stack.consume_reference(bucket.bucket_arn, ReferenceStrength.WEAK)
)
java
Bucket bucket;
Stack consumer;


CfnOutput.Builder.create(consumer, "BucketArn")
        .value(Stack.consumeReference(bucket.getBucketArn(), ReferenceStrength.WEAK))
        .build();
csharp
Bucket bucket;
Stack consumer;


new CfnOutput(consumer, "BucketArn", new CfnOutputProps {
    Value = Stack.ConsumeReference(bucket.BucketArn, ReferenceStrength.WEAK)
});
go
var bucket Bucket
var consumer Stack


awscdk.NewCfnOutput(consumer, jsii.String("BucketArn"), &CfnOutputProps{
	Value: awscdk.*stack_ConsumeReference(bucket.bucketArn, awscdk.ReferenceStrength_WEAK),
})

DEPLOYMENT 3: remove the resource or the reference as needed.

Durations ​

To make specifications of time intervals unambiguous, a single class called Duration is used throughout the AWS Construct Library by all constructs that that take a time interval as a parameter (be it for a timeout, a rate, or something else).

An instance of Duration is constructed by using one of the static factory methods on it:

ts
Duration.seconds(300)   // 5 minutes
Duration.minutes(5)     // 5 minutes
Duration.hours(1)       // 1 hour
Duration.days(7)        // 7 days
Duration.parse('PT5M')  // 5 minutes
python
Duration.seconds(300) # 5 minutes
Duration.minutes(5) # 5 minutes
Duration.hours(1) # 1 hour
Duration.days(7) # 7 days
Duration.parse("PT5M")
java
Duration.seconds(300); // 5 minutes
Duration.minutes(5); // 5 minutes
Duration.hours(1); // 1 hour
Duration.days(7); // 7 days
Duration.parse("PT5M");
csharp
Duration.Seconds(300); // 5 minutes
Duration.Minutes(5); // 5 minutes
Duration.Hours(1); // 1 hour
Duration.Days(7); // 7 days
Duration.Parse("PT5M");
go
awscdk.Duration_Seconds(jsii.Number(300)) // 5 minutes
awscdk.Duration_Minutes(jsii.Number(5)) // 5 minutes
awscdk.Duration_Hours(jsii.Number(1)) // 1 hour
awscdk.Duration_Days(jsii.Number(7)) // 7 days
awscdk.Duration_Parse(jsii.String("PT5M"))

Durations can be added or subtracted together:

ts
Duration.minutes(1).plus(Duration.seconds(60)); // 2 minutes
Duration.minutes(5).minus(Duration.seconds(10)); // 290 secondes
python
Duration.minutes(1).plus(Duration.seconds(60)) # 2 minutes
Duration.minutes(5).minus(Duration.seconds(10))
java
Duration.minutes(1).plus(Duration.seconds(60)); // 2 minutes
Duration.minutes(5).minus(Duration.seconds(10));
csharp
Duration.Minutes(1).Plus(Duration.Seconds(60)); // 2 minutes
Duration.Minutes(5).Minus(Duration.Seconds(10));
go
awscdk.Duration_Minutes(jsii.Number(1)).Plus(awscdk.Duration_Seconds(jsii.Number(60))) // 2 minutes
awscdk.Duration_Minutes(jsii.Number(5)).Minus(awscdk.Duration_Seconds(jsii.Number(10)))

Size (Digital Information Quantity) ​

To make specification of digital storage quantities unambiguous, a class called Size is available.

An instance of Size is initialized through one of its static factory methods:

ts
Size.kibibytes(200) // 200 KiB
Size.mebibytes(5)   // 5 MiB
Size.gibibytes(40)  // 40 GiB
Size.tebibytes(200) // 200 TiB
Size.pebibytes(3)   // 3 PiB
python
Size.kibibytes(200) # 200 KiB
Size.mebibytes(5) # 5 MiB
Size.gibibytes(40) # 40 GiB
Size.tebibytes(200) # 200 TiB
Size.pebibytes(3)
java
Size.kibibytes(200); // 200 KiB
Size.mebibytes(5); // 5 MiB
Size.gibibytes(40); // 40 GiB
Size.tebibytes(200); // 200 TiB
Size.pebibytes(3);
csharp
Size.Kibibytes(200); // 200 KiB
Size.Mebibytes(5); // 5 MiB
Size.Gibibytes(40); // 40 GiB
Size.Tebibytes(200); // 200 TiB
Size.Pebibytes(3);
go
awscdk.Size_Kibibytes(jsii.Number(200)) // 200 KiB
awscdk.Size_Mebibytes(jsii.Number(5)) // 5 MiB
awscdk.Size_Gibibytes(jsii.Number(40)) // 40 GiB
awscdk.Size_Tebibytes(jsii.Number(200)) // 200 TiB
awscdk.Size_Pebibytes(jsii.Number(3))

Instances of Size created with one of the units can be converted into others. By default, conversion to a higher unit will fail if the conversion does not produce a whole number. This can be overridden by unsetting integral property.

ts
Size.mebibytes(2).toKibibytes()                                             // yields 2048
Size.kibibytes(2050).toMebibytes({ rounding: SizeRoundingBehavior.FLOOR })  // yields 2
python
Size.mebibytes(2).to_kibibytes() # yields 2048
Size.kibibytes(2050).to_mebibytes(rounding=SizeRoundingBehavior.FLOOR)
java
Size.mebibytes(2).toKibibytes(); // yields 2048
Size.kibibytes(2050).toMebibytes(SizeConversionOptions.builder().rounding(SizeRoundingBehavior.FLOOR).build());
csharp
Size.Mebibytes(2).ToKibibytes(); // yields 2048
Size.Kibibytes(2050).ToMebibytes(new SizeConversionOptions { Rounding = SizeRoundingBehavior.FLOOR });
go
awscdk.Size_Mebibytes(jsii.Number(2)).ToKibibytes() // yields 2048
awscdk.Size_Kibibytes(jsii.Number(2050)).ToMebibytes(&SizeConversionOptions{
	Rounding: awscdk.SizeRoundingBehavior_FLOOR,
})

Bitrate ​

To make specification of bitrate values unambiguous, a class called Bitrate is available.

An instance of Bitrate is initialized through one of its static factory methods:

ts
Bitrate.bps(5000)   // 5,000 bits per second
Bitrate.kbps(500)   // 500 kilobits per second
Bitrate.mbps(10)    // 10 megabits per second
Bitrate.gbps(1)     // 1 gigabit per second
python
Bitrate.bps(5000) # 5,000 bits per second
Bitrate.kbps(500) # 500 kilobits per second
Bitrate.mbps(10) # 10 megabits per second
Bitrate.gbps(1)
java
Bitrate.bps(5000); // 5,000 bits per second
Bitrate.kbps(500); // 500 kilobits per second
Bitrate.mbps(10); // 10 megabits per second
Bitrate.gbps(1);
csharp
Bitrate.Bps(5000); // 5,000 bits per second
Bitrate.Kbps(500); // 500 kilobits per second
Bitrate.Mbps(10); // 10 megabits per second
Bitrate.Gbps(1);
go
awscdk.Bitrate_Bps(jsii.Number(5000)) // 5,000 bits per second
awscdk.Bitrate_Kbps(jsii.Number(500)) // 500 kilobits per second
awscdk.Bitrate_Mbps(jsii.Number(10)) // 10 megabits per second
awscdk.Bitrate_Gbps(jsii.Number(1))

Instances of Bitrate created with one of the units can be converted into others:

ts
Bitrate.mbps(10).toBps()    // yields 10000000
Bitrate.mbps(10).toKbps()  // yields 10000
python
Bitrate.mbps(10).to_bps() # yields 10000000
Bitrate.mbps(10).to_kbps()
java
Bitrate.mbps(10).toBps(); // yields 10000000
Bitrate.mbps(10).toKbps();
csharp
Bitrate.Mbps(10).ToBps(); // yields 10000000
Bitrate.Mbps(10).ToKbps();
go
awscdk.Bitrate_Mbps(jsii.Number(10)).ToBps() // yields 10000000
awscdk.Bitrate_Mbps(jsii.Number(10)).ToKbps()

Secrets ​

To help avoid accidental storage of secrets as plain text, we use the SecretValue type to represent secrets. Any construct that takes a value that should be a secret (such as a password or an access key) will take a parameter of type SecretValue.

The best practice is to store secrets in AWS Secrets Manager and reference them using SecretValue.secretsManager:

ts
const secret = SecretValue.secretsManager('secretId', {
  jsonField: 'password', // optional: key of a JSON field to retrieve (defaults to all content),
  versionId: 'id',       // optional: id of the version (default AWSCURRENT)
  versionStage: 'stage', // optional: version stage name (default AWSCURRENT)
});
python
secret = SecretValue.secrets_manager("secretId",
    json_field="password",  # optional: key of a JSON field to retrieve (defaults to all content),
    version_id="id",  # optional: id of the version (default AWSCURRENT)
    version_stage="stage"
)
java
SecretValue secret = SecretValue.secretsManager("secretId", SecretsManagerSecretOptions.builder()
        .jsonField("password") // optional: key of a JSON field to retrieve (defaults to all content),
        .versionId("id") // optional: id of the version (default AWSCURRENT)
        .versionStage("stage")
        .build());
csharp
var secret = SecretValue.SecretsManager("secretId", new SecretsManagerSecretOptions {
    JsonField = "password",  // optional: key of a JSON field to retrieve (defaults to all content),
    VersionId = "id",  // optional: id of the version (default AWSCURRENT)
    VersionStage = "stage"
});
go
secret := awscdk.SecretValue_SecretsManager(jsii.String("secretId"), &SecretsManagerSecretOptions{
	JsonField: jsii.String("password"),
	 // optional: key of a JSON field to retrieve (defaults to all content),
	VersionId: jsii.String("id"),
	 // optional: id of the version (default AWSCURRENT)
	VersionStage: jsii.String("stage"),
})

Using AWS Secrets Manager is the recommended way to reference secrets in a CDK app. SecretValue also supports the following secret sources:

  • SecretValue.unsafePlainText(secret): stores the secret as plain text in your app and the resulting template (not recommended).
  • SecretValue.secretsManager(secret): refers to a secret stored in Secrets Manager
  • SecretValue.ssmSecure(param, version): refers to a secret stored as a SecureString in the SSM Parameter Store. If you don't specify the exact version, AWS CloudFormation uses the latest version of the parameter.
  • SecretValue.cfnParameter(param): refers to a secret passed through a CloudFormation parameter (must have NoEcho: true).
  • SecretValue.cfnDynamicReference(dynref): refers to a secret described by a CloudFormation dynamic reference (used by ssmSecure and secretsManager).
  • SecretValue.resourceAttribute(attr): refers to a secret returned from a CloudFormation resource creation.

SecretValues should only be passed to constructs that accept properties of type SecretValue. These constructs are written to ensure your secrets will not be exposed where they shouldn't be. If you try to use a SecretValue in a different location, an error about unsafe secret usage will be thrown at synthesis time.

If you rotate the secret's value in Secrets Manager, you must also change at least one property on the resource where you are using the secret, to force CloudFormation to re-read the secret.

SecretValue.ssmSecure() is only supported for a limited set of resources. Click here for a list of supported resources and properties.

SecretValue.cfnDynamicReferenceKey takes the same parameters as SecretValue.secretsManager and returns a key which can be used within a dynamic reference to dynamically load a secret from AWS Secrets Manager.

ARN manipulation ​

Sometimes you will need to put together or pick apart Amazon Resource Names (ARNs). The functions stack.formatArn() and stack.splitArn() exist for this purpose.

formatArn() can be used to build an ARN from components. It will automatically use the region and account of the stack you're calling it on:

ts
declare const stack: Stack;

// Builds "arn:<PARTITION>:lambda:<REGION>:<ACCOUNT>:function:MyFunction"
stack.formatArn({
  service: 'lambda',
  resource: 'function',
  arnFormat: ArnFormat.COLON_RESOURCE_NAME,
  resourceName: 'MyFunction'
});
python
# stack: Stack


# Builds "arn:<PARTITION>:lambda:<REGION>:<ACCOUNT>:function:MyFunction"
stack.format_arn(
    service="lambda",
    resource="function",
    arn_format=ArnFormat.COLON_RESOURCE_NAME,
    resource_name="MyFunction"
)
java
Stack stack;


// Builds "arn:<PARTITION>:lambda:<REGION>:<ACCOUNT>:function:MyFunction"
stack.formatArn(ArnComponents.builder()
        .service("lambda")
        .resource("function")
        .arnFormat(ArnFormat.COLON_RESOURCE_NAME)
        .resourceName("MyFunction")
        .build());
csharp
Stack stack;


// Builds "arn:<PARTITION>:lambda:<REGION>:<ACCOUNT>:function:MyFunction"
stack.FormatArn(new ArnComponents {
    Service = "lambda",
    Resource = "function",
    ArnFormat = ArnFormat.COLON_RESOURCE_NAME,
    ResourceName = "MyFunction"
});
go
var stack Stack


// Builds "arn:<PARTITION>:lambda:<REGION>:<ACCOUNT>:function:MyFunction"
stack.FormatArn(&ArnComponents{
	Service: jsii.String("lambda"),
	Resource: jsii.String("function"),
	ArnFormat: awscdk.ArnFormat_COLON_RESOURCE_NAME,
	ResourceName: jsii.String("MyFunction"),
})

splitArn() can be used to get a single component from an ARN. splitArn() will correctly deal with both literal ARNs and deploy-time values (tokens), but in case of a deploy-time value be aware that the result will be another deploy-time value which cannot be inspected in the CDK application.

ts
declare const stack: Stack;

// Extracts the function name out of an AWS Lambda Function ARN
const arnComponents = stack.splitArn(arn, ArnFormat.COLON_RESOURCE_NAME);
const functionName = arnComponents.resourceName;
python
# stack: Stack


# Extracts the function name out of an AWS Lambda Function ARN
arn_components = stack.split_arn(arn, ArnFormat.COLON_RESOURCE_NAME)
function_name = arn_components.resource_name
java
Stack stack;


// Extracts the function name out of an AWS Lambda Function ARN
ArnComponents arnComponents = stack.splitArn(arn, ArnFormat.COLON_RESOURCE_NAME);
String functionName = arnComponents.getResourceName();
csharp
Stack stack;


// Extracts the function name out of an AWS Lambda Function ARN
var arnComponents = stack.SplitArn(arn, ArnFormat.COLON_RESOURCE_NAME);
var functionName = arnComponents.ResourceName;
go
var stack Stack


// Extracts the function name out of an AWS Lambda Function ARN
arnComponents := stack.SplitArn(arn, awscdk.ArnFormat_COLON_RESOURCE_NAME)
functionName := arnComponents.ResourceName

Note that the format of the resource separator depends on the service and may be any of the values supported by ArnFormat. When dealing with these functions, it is important to know the format of the ARN you are dealing with.

For an exhaustive list of ARN formats used in AWS, see AWS ARNs and Namespaces in the AWS General Reference.

Some L1 constructs also have an auto-generated static arnFor<ResourceName>() method that can be used to generate ARNs for resources of that type. For example, sns.Topic.arnForTopic(topic) can be used to generate an ARN for a given topic. Note that the parameter to this method is of type ITopicRef, which means that it can be used with both Topic (L2) and CfnTopic (L1) constructs.

Dependencies ​

Construct Dependencies ​

Sometimes AWS resources depend on other resources, and the creation of one resource must be completed before the next one can be started.

In general, CloudFormation will correctly infer the dependency relationship between resources based on the property values that are used. In the cases where it doesn't, the AWS Construct Library will add the dependency relationship for you.

If you need to add an ordering dependency that is not automatically inferred, you do so by adding a dependency relationship using constructA.node.addDependency(constructB). This will add a dependency relationship between all resources in the scope of constructA and all resources in the scope of constructB.

If you want a single object to represent a set of constructs that are not necessarily in the same scope, you can use a DependencyGroup. The following creates a single object that represents a dependency on two constructs, constructB and constructC:

ts
// Declare the dependable object
const bAndC = new DependencyGroup();
bAndC.add(constructB);
bAndC.add(constructC);

// Take the dependency
constructA.node.addDependency(bAndC);
python
# Declare the dependable object
b_and_c = DependencyGroup()
b_and_c.add(construct_b)
b_and_c.add(construct_c)

# Take the dependency
construct_a.node.add_dependency(b_and_c)
java
// Declare the dependable object
DependencyGroup bAndC = new DependencyGroup();
bAndC.add(constructB);
bAndC.add(constructC);

// Take the dependency
constructA.node.addDependency(bAndC);
csharp
// Declare the dependable object
var bAndC = new DependencyGroup();
bAndC.Add(constructB);
bAndC.Add(constructC);

// Take the dependency
constructA.Node.AddDependency(bAndC);
go
// Declare the dependable object
bAndC := constructs.NewDependencyGroup()
bAndC.Add(constructB)
bAndC.Add(constructC)

// Take the dependency
constructA.Node.AddDependency(bAndC)

Stack Dependencies ​

Two different stack instances can have a dependency on one another. This happens when an resource from one stack is referenced in another stack. In that case, CDK records the cross-stack referencing of resources, automatically produces the right CloudFormation primitives, and adds a dependency between the two stacks. You can also manually add a dependency between two stacks by using the stackA.addStackDependency(stackB) method.

A stack dependency has the following implications:

  • Cyclic dependencies are not allowed, so if stackA is using resources from stackB, the reverse is not possible anymore.
  • Stacks with dependencies between them are treated specially by the CDK toolkit:
    • If stackA depends on stackB, running cdk deploy stackA will also automatically deploy stackB.
    • stackB's deployment will be performed before stackA's deployment.

CfnResource Dependencies ​

To make declaring dependencies between CfnResource objects easier, you can declare dependencies from one CfnResource object on another by using the cfnResource1.addResourceDependency(cfnResource2) method. This method will work for resources both within the same stack and across stacks as it detects the relative location of the two resources and adds the dependency either to the resource or between the relevant stacks, as appropriate. If more complex logic is in needed, you can similarly remove, replace, or view dependencies between CfnResource objects with the CfnResource removeResourceDependency, replaceDependency, and obtainDependencies methods, respectively.

Custom Resources ​

Custom Resources are CloudFormation resources that are implemented by arbitrary user code. They can do arbitrary lookups or modifications during a CloudFormation deployment.

Custom resources are backed by custom resource providers. Commonly, these are Lambda Functions that are deployed in the same deployment as the one that defines the custom resource itself, but they can also be backed by Lambda Functions deployed previously, or code responding to SNS Topic events running on EC2 instances in a completely different account. For more information on custom resource providers, see the next section.

Once you have a provider, each definition of a CustomResource construct represents one invocation. A single provider can be used for the implementation of arbitrarily many custom resource definitions. A single definition looks like this:

ts
new CustomResource(this, 'MyMagicalResource', {
  resourceType: 'Custom::MyCustomResource', // must start with 'Custom::'

  // the resource properties
  // properties like serviceToken or serviceTimeout are ported into properties automatically
  // try not to use key names similar to these or there will be a risk of overwriting those values
  properties: {
    Property1: 'foo',
    Property2: 'bar',
  },

  // the ARN of the provider (SNS/Lambda) which handles
  // CREATE, UPDATE or DELETE events for this resource type
  // see next section for details
  serviceToken: 'ARN',

  // the maximum time, in seconds, that can elapse before a custom resource operation times out.
  serviceTimeout: Duration.seconds(60),
});
python
CustomResource(self, "MyMagicalResource",
    resource_type="Custom::MyCustomResource",  # must start with 'Custom::'

    # the resource properties
    # properties like serviceToken or serviceTimeout are ported into properties automatically
    # try not to use key names similar to these or there will be a risk of overwriting those values
    properties={
        "Property1": "foo",
        "Property2": "bar"
    },

    # the ARN of the provider (SNS/Lambda) which handles
    # CREATE, UPDATE or DELETE events for this resource type
    # see next section for details
    service_token="ARN",

    # the maximum time, in seconds, that can elapse before a custom resource operation times out.
    service_timeout=Duration.seconds(60)
)
java
CustomResource.Builder.create(this, "MyMagicalResource")
        .resourceType("Custom::MyCustomResource") // must start with 'Custom::'

        // the resource properties
        // properties like serviceToken or serviceTimeout are ported into properties automatically
        // try not to use key names similar to these or there will be a risk of overwriting those values
        .properties(Map.of(
                "Property1", "foo",
                "Property2", "bar"))

        // the ARN of the provider (SNS/Lambda) which handles
        // CREATE, UPDATE or DELETE events for this resource type
        // see next section for details
        .serviceToken("ARN")

        // the maximum time, in seconds, that can elapse before a custom resource operation times out.
        .serviceTimeout(Duration.seconds(60))
        .build();
csharp
new CustomResource(this, "MyMagicalResource", new CustomResourceProps {
    ResourceType = "Custom::MyCustomResource",  // must start with 'Custom::'

    // the resource properties
    // properties like serviceToken or serviceTimeout are ported into properties automatically
    // try not to use key names similar to these or there will be a risk of overwriting those values
    Properties = new Dictionary<string, object> {
        { "Property1", "foo" },
        { "Property2", "bar" }
    },

    // the ARN of the provider (SNS/Lambda) which handles
    // CREATE, UPDATE or DELETE events for this resource type
    // see next section for details
    ServiceToken = "ARN",

    // the maximum time, in seconds, that can elapse before a custom resource operation times out.
    ServiceTimeout = Duration.Seconds(60)
});
go
awscdk.NewCustomResource(this, jsii.String("MyMagicalResource"), &CustomResourceProps{
	ResourceType: jsii.String("Custom::MyCustomResource"),
	 // must start with 'Custom::'

	// the resource properties
	// properties like serviceToken or serviceTimeout are ported into properties automatically
	// try not to use key names similar to these or there will be a risk of overwriting those values
	Properties: map[string]interface{}{
		"Property1": jsii.String("foo"),
		"Property2": jsii.String("bar"),
	},

	// the ARN of the provider (SNS/Lambda) which handles
	// CREATE, UPDATE or DELETE events for this resource type
	// see next section for details
	ServiceToken: jsii.String("ARN"),

	// the maximum time, in seconds, that can elapse before a custom resource operation times out.
	ServiceTimeout: awscdk.Duration_Seconds(jsii.Number(60)),
})

Custom Resource Providers ​

Custom resources are backed by a custom resource provider which can be implemented in one of the following ways. The following table compares the various provider types (ordered from low-level to high-level):

ProviderCompute TypeError HandlingSubmit to CloudFormationMax TimeoutLanguageFootprint
sns.TopicSelf-managedManualManualUnlimitedAnyDepends
lambda.FunctionAWS LambdaManualManual15minAnySmall
core.CustomResourceProviderAWS LambdaAutoAuto15minNode.jsSmall
custom-resources.ProviderAWS LambdaAutoAutoUnlimited AsyncAnyLarge

Legend:

  • Compute type: which type of compute can be used to execute the handler.
  • Error Handling: whether errors thrown by handler code are automatically trapped and a FAILED response is submitted to CloudFormation. If this is "Manual", developers must take care of trapping errors. Otherwise, events could cause stacks to hang.
  • Submit to CloudFormation: whether the framework takes care of submitting SUCCESS/FAILED responses to CloudFormation through the event's response URL.
  • Max Timeout: maximum allows/possible timeout.
  • Language: which programming languages can be used to implement handlers.
  • Footprint: how many resources are used by the provider framework itself.

A note about singletons ​

When defining resources for a custom resource provider, you will likely want to define them as a stack singleton so that only a single instance of the provider is created in your stack and which is used by all custom resources of that type.

Here is a basic pattern for defining stack singletons in the CDK. The following examples ensures that only a single SNS topic is defined:

ts
function getOrCreate(scope: Construct): sns.Topic {
  const stack = Stack.of(scope);
  const uniqueid = 'GloballyUniqueIdForSingleton'; // For example, a UUID from `uuidgen`
  const existing = stack.node.tryFindChild(uniqueid);
  if (existing) {
    return existing as sns.Topic;
  }
  return new sns.Topic(stack, uniqueid);
}
python
def get_or_create(self, scope):
    stack = Stack.of(scope)
    uniqueid = "GloballyUniqueIdForSingleton" # For example, a UUID from `uuidgen`
    existing = stack.node.try_find_child(uniqueid)
    if existing:
        return existing
    return sns.Topic(stack, uniqueid)
java
public Topic getOrCreate(Construct scope) {
    Stack stack = Stack.of(scope);
    String uniqueid = "GloballyUniqueIdForSingleton"; // For example, a UUID from `uuidgen`
    IConstruct existing = stack.node.tryFindChild(uniqueid);
    if (existing) {
        return (Topic)existing;
    }
    return new Topic(stack, uniqueid);
}
csharp
public Topic GetOrCreate(Construct scope)
{
    var stack = Stack.Of(scope);
    var uniqueid = "GloballyUniqueIdForSingleton"; // For example, a UUID from `uuidgen`
    var existing = stack.Node.TryFindChild(uniqueid);
    if (existing)
    {
        return (Topic)existing;
    }
    return new Topic(stack, uniqueid);
}
go
func getOrCreate(scope Construct) Topic {
	stack := awscdk.stack_Of(*scope)
	uniqueid := "GloballyUniqueIdForSingleton" // For example, a UUID from `uuidgen`
	existing := stack.Node.TryFindChild(uniqueid)
	if existing {
		return existing.(Topic)
	}
	return sns.NewTopic(stack, uniqueid)
}

Amazon SNS Topic ​

Every time a resource event occurs (CREATE/UPDATE/DELETE), an SNS notification is sent to the SNS topic. Users must process these notifications (e.g. through a fleet of worker hosts) and submit success/failure responses to the CloudFormation service.

You only need to use this type of provider if your custom resource cannot run on AWS Lambda, for reasons other than the 15 minute timeout. If you are considering using this type of provider because you want to write a custom resource provider that may need to wait for more than 15 minutes for the API calls to stabilize, have a look at the custom-resources module first.

Refer to the CloudFormation Custom Resource documentation for information on the contract your custom resource needs to adhere to.

Set serviceToken to topic.topicArn in order to use this provider:

ts
const topic = new sns.Topic(this, 'MyProvider');

new CustomResource(this, 'MyResource', {
  serviceToken: topic.topicArn
});
python
topic = sns.Topic(self, "MyProvider")

CustomResource(self, "MyResource",
    service_token=topic.topic_arn
)
java
Topic topic = new Topic(this, "MyProvider");

CustomResource.Builder.create(this, "MyResource")
        .serviceToken(topic.getTopicArn())
        .build();
csharp
var topic = new Topic(this, "MyProvider");

new CustomResource(this, "MyResource", new CustomResourceProps {
    ServiceToken = topic.TopicArn
});
go
topic := sns.NewTopic(this, jsii.String("MyProvider"))

awscdk.NewCustomResource(this, jsii.String("MyResource"), &CustomResourceProps{
	ServiceToken: topic.topicArn,
})

AWS Lambda Function ​

An AWS lambda function is called directly by CloudFormation for all resource events. The handler must take care of explicitly submitting a success/failure response to the CloudFormation service and handle various error cases.

We do not recommend you use this provider type. The CDK has wrappers around Lambda Functions that make them easier to work with.

If you do want to use this provider, refer to the CloudFormation Custom Resource documentation for information on the contract your custom resource needs to adhere to.

Set serviceToken to lambda.functionArn to use this provider:

ts
const fn = new lambda.SingletonFunction(this, 'MyProvider', functionProps);

new CustomResource(this, 'MyResource', {
  serviceToken: fn.functionArn,
});
python
fn = lambda_.SingletonFunction(self, "MyProvider", function_props)

CustomResource(self, "MyResource",
    service_token=fn.function_arn
)
java
SingletonFunction fn = new SingletonFunction(this, "MyProvider", functionProps);

CustomResource.Builder.create(this, "MyResource")
        .serviceToken(fn.getFunctionArn())
        .build();
csharp
var fn = new SingletonFunction(this, "MyProvider", functionProps);

new CustomResource(this, "MyResource", new CustomResourceProps {
    ServiceToken = fn.FunctionArn
});
go
fn := lambda.NewSingletonFunction(this, jsii.String("MyProvider"), functionProps)

awscdk.NewCustomResource(this, jsii.String("MyResource"), &CustomResourceProps{
	ServiceToken: fn.FunctionArn,
})

The core.CustomResourceProvider class ​

The class @aws-cdk/core.CustomResourceProvider offers a basic low-level framework designed to implement simple and slim custom resource providers. It currently only supports Node.js-based user handlers, represents permissions as raw JSON blobs instead of iam.PolicyStatement objects, and it does not have support for asynchronous waiting (handler cannot exceed the 15min lambda timeout). The CustomResourceProviderRuntime supports runtime nodejs12.x, nodejs14.x, nodejs16.x, nodejs18.x, nodejs20.x, nodejs22.x and nodejs24.x.

As an application builder, we do not recommend you use this provider type. This provider exists purely for custom resources that are part of the AWS Construct Library.

The custom-resources provider is more convenient to work with and more fully-featured.

The provider has a built-in singleton method which uses the resource type as a stack-unique identifier and returns the service token:

ts
const serviceToken = CustomResourceProvider.getOrCreate(this, 'Custom::MyCustomResourceType', {
  codeDirectory: `${__dirname}/my-handler`,
  runtime: CustomResourceProviderRuntime.NODEJS_24_X,
  description: "Lambda function created by the custom resource provider",
});

new CustomResource(this, 'MyResource', {
  resourceType: 'Custom::MyCustomResourceType',
  serviceToken: serviceToken
});
python
service_token = CustomResourceProvider.get_or_create(self, "Custom::MyCustomResourceType",
    code_directory=f"{__dirname}/my-handler",
    runtime=CustomResourceProviderRuntime.NODEJS_24_X,
    description="Lambda function created by the custom resource provider"
)

CustomResource(self, "MyResource",
    resource_type="Custom::MyCustomResourceType",
    service_token=service_token
)
java
String serviceToken = CustomResourceProvider.getOrCreate(this, "Custom::MyCustomResourceType", CustomResourceProviderProps.builder()
        .codeDirectory(String.format("%s/my-handler", __dirname))
        .runtime(CustomResourceProviderRuntime.NODEJS_24_X)
        .description("Lambda function created by the custom resource provider")
        .build());

CustomResource.Builder.create(this, "MyResource")
        .resourceType("Custom::MyCustomResourceType")
        .serviceToken(serviceToken)
        .build();
csharp
var serviceToken = CustomResourceProvider.GetOrCreate(this, "Custom::MyCustomResourceType", new CustomResourceProviderProps {
    CodeDirectory = $"{__dirname}/my-handler",
    Runtime = CustomResourceProviderRuntime.NODEJS_24_X,
    Description = "Lambda function created by the custom resource provider"
});

new CustomResource(this, "MyResource", new CustomResourceProps {
    ResourceType = "Custom::MyCustomResourceType",
    ServiceToken = serviceToken
});
go
serviceToken := awscdk.CustomResourceProvider_GetOrCreate(this, jsii.String("Custom::MyCustomResourceType"), &CustomResourceProviderProps{
	CodeDirectory: fmt.Sprintf("%v/my-handler", __dirname),
	Runtime: awscdk.CustomResourceProviderRuntime_NODEJS_24_X,
	Description: jsii.String("Lambda function created by the custom resource provider"),
})

awscdk.NewCustomResource(this, jsii.String("MyResource"), &CustomResourceProps{
	ResourceType: jsii.String("Custom::MyCustomResourceType"),
	ServiceToken: serviceToken,
})

The directory (my-handler in the above example) must include an index.js file. It cannot import external dependencies or files outside this directory. It must export an async function named handler. This function accepts the CloudFormation resource event object and returns an object with the following structure:

js
exports.handler = async function(event) {
  const id = event.PhysicalResourceId; // only for "Update" and "Delete"
  const props = event.ResourceProperties;
  const oldProps = event.OldResourceProperties; // only for "Update"s

  switch (event.RequestType) {
    case "Create":
      // ...

    case "Update":
      // ...

      // if an error is thrown, a FAILED response will be submitted to CFN
      throw new Error('Failed!');

    case "Delete":
      // ...
  }

  return {
    // (optional) the value resolved from `resource.ref`
    // defaults to "event.PhysicalResourceId" or "event.RequestId"
    PhysicalResourceId: "REF",

    // (optional) calling `resource.getAtt("Att1")` on the custom resource in the CDK app
    // will return the value "BAR".
    Data: {
      Att1: "BAR",
      Att2: "BAZ"
    },

    // (optional) user-visible message
    Reason: "User-visible message",

    // (optional) hides values from the console
    NoEcho: true
  };
}

Here is an complete example of a custom resource that summarizes two numbers:

sum-handler/index.js:

js
exports.handler = async (e) => {
  return {
    Data: {
      Result: e.ResourceProperties.lhs + e.ResourceProperties.rhs,
    },
  };
};

sum.ts:

ts
import { Construct } from 'constructs';
import {
  CustomResource,
  CustomResourceProvider,
  CustomResourceProviderRuntime,
  Token,
} from 'aws-cdk-lib';

export interface SumProps {
  readonly lhs: number;
  readonly rhs: number;
}

export class Sum extends Construct {
  public readonly result: number;

  constructor(scope: Construct, id: string, props: SumProps) {
    super(scope, id);

    const resourceType = 'Custom::Sum';
    const serviceToken = CustomResourceProvider.getOrCreate(this, resourceType, {
      codeDirectory: `${__dirname}/sum-handler`,
      runtime: CustomResourceProviderRuntime.NODEJS_22_X,
    });

    const resource = new CustomResource(this, 'Resource', {
      resourceType: resourceType,
      serviceToken: serviceToken,
      properties: {
        lhs: props.lhs,
        rhs: props.rhs
      }
    });

    this.result = Token.asNumber(resource.getAtt('Result'));
  }
}
python
from constructs import Construct
from aws_cdk import CustomResource, CustomResourceProvider, CustomResourceProviderRuntime, Token

class Sum(Construct):

    def __init__(self, scope, id, *, lhs, rhs):
        super().__init__(scope, id)

        resource_type = "Custom::Sum"
        service_token = CustomResourceProvider.get_or_create(self, resource_type,
            code_directory=f"{__dirname}/sum-handler",
            runtime=CustomResourceProviderRuntime.NODEJS_22_X
        )

        resource = CustomResource(self, "Resource",
            resource_type=resource_type,
            service_token=service_token,
            properties={
                "lhs": lhs,
                "rhs": rhs
            }
        )

        self.result = Token.as_number(resource.get_att("Result"))
java
import software.constructs.Construct;
import software.amazon.awscdk.CustomResource;
import software.amazon.awscdk.CustomResourceProvider;
import software.amazon.awscdk.CustomResourceProviderRuntime;
import software.amazon.awscdk.Token;

public class SumProps {
    private Number lhs;
    public Number getLhs() {
        return this.lhs;
    }
    public SumProps lhs(Number lhs) {
        this.lhs = lhs;
        return this;
    }
    private Number rhs;
    public Number getRhs() {
        return this.rhs;
    }
    public SumProps rhs(Number rhs) {
        this.rhs = rhs;
        return this;
    }
}

public class Sum extends Construct {
    public final Number result;

    public Sum(Construct scope, String id, SumProps props) {
        super(scope, id);

        String resourceType = "Custom::Sum";
        String serviceToken = CustomResourceProvider.getOrCreate(this, resourceType, CustomResourceProviderProps.builder()
                .codeDirectory(String.format("%s/sum-handler", __dirname))
                .runtime(CustomResourceProviderRuntime.NODEJS_22_X)
                .build());

        CustomResource resource = CustomResource.Builder.create(this, "Resource")
                .resourceType(resourceType)
                .serviceToken(serviceToken)
                .properties(Map.of(
                        "lhs", props.getLhs(),
                        "rhs", props.getRhs()))
                .build();

        this.result = Token.asNumber(resource.getAtt("Result"));
    }
}
csharp
using Constructs;
using Amazon.CDK;

class SumProps
{
    public int Lhs { get; set; }
    public int Rhs { get; set; }
}

class Sum : Construct
{
    public int Result { get; }

    public Sum(Construct scope, string id, SumProps props) : base(scope, id)
    {

        var resourceType = "Custom::Sum";
        var serviceToken = CustomResourceProvider.GetOrCreate(this, resourceType, new CustomResourceProviderProps {
            CodeDirectory = $"{__dirname}/sum-handler",
            Runtime = CustomResourceProviderRuntime.NODEJS_22_X
        });

        var resource = new CustomResource(this, "Resource", new CustomResourceProps {
            ResourceType = resourceType,
            ServiceToken = serviceToken,
            Properties = new Dictionary<string, object> {
                { "lhs", props.Lhs },
                { "rhs", props.Rhs }
            }
        });

        Result = Token.AsNumber(resource.GetAtt("Result"));
    }
}
go
import "github.com/aws/constructs-go/constructs"
import "github.com/aws/aws-cdk-go/awscdk"

type SumProps struct {
	lhs *f64
	rhs *f64
}

type Sum struct {
	Construct
	result *f64
}result *f64

func NewSum(scope Construct, id *string, props SumProps) *Sum {
	this := &Sum{}
	newConstruct_Override(this, scope, id)

	resourceType := "Custom::Sum"
	serviceToken := awscdk.CustomResourceProvider_GetOrCreate(this, resourceType, &CustomResourceProviderProps{
		CodeDirectory: fmt.Sprintf("%v/sum-handler", __dirname),
		Runtime: awscdk.CustomResourceProviderRuntime_NODEJS_22_X,
	})

	resource := awscdk.NewCustomResource(this, jsii.String("Resource"), &CustomResourceProps{
		ResourceType: resourceType,
		ServiceToken: serviceToken,
		Properties: map[string]interface{}{
			"lhs": props.lhs,
			"rhs": props.rhs,
		},
	})

	this.result = awscdk.Token_AsNumber(resource.GetAtt(jsii.String("Result")))
	return this
}

Usage will look like this:

ts
const sum = new Sum(this, 'MySum', { lhs: 40, rhs: 2 });
new CfnOutput(this, 'Result', { value: Token.asString(sum.result) });
python
sum = Sum(self, "MySum", lhs=40, rhs=2)
CfnOutput(self, "Result", value=Token.as_string(sum.result))
java
Sum sum = new Sum(this, "MySum", new SumProps().lhs(40).rhs(2));
CfnOutput.Builder.create(this, "Result").value(Token.asString(sum.getResult())).build();
csharp
var sum = new Sum(this, "MySum", new SumProps { Lhs = 40, Rhs = 2 });
new CfnOutput(this, "Result", new CfnOutputProps { Value = Token.AsString(sum.Result) });
go
sum := NewSum(this, jsii.String("MySum"), &sumProps{
	lhs: jsii.Number(40),
	rhs: jsii.Number(2),
})
awscdk.NewCfnOutput(this, jsii.String("Result"), &CfnOutputProps{
	Value: awscdk.Token_AsString(sum.result),
})

To access the ARN of the provider's AWS Lambda function role, use the getOrCreateProvider() built-in singleton method:

ts
const provider = CustomResourceProvider.getOrCreateProvider(this, 'Custom::MyCustomResourceType', {
  codeDirectory: `${__dirname}/my-handler`,
  runtime: CustomResourceProviderRuntime.NODEJS_22_X,
});

const roleArn = provider.roleArn;
python
provider = CustomResourceProvider.get_or_create_provider(self, "Custom::MyCustomResourceType",
    code_directory=f"{__dirname}/my-handler",
    runtime=CustomResourceProviderRuntime.NODEJS_22_X
)

role_arn = provider.role_arn
java
CustomResourceProvider provider = CustomResourceProvider.getOrCreateProvider(this, "Custom::MyCustomResourceType", CustomResourceProviderProps.builder()
        .codeDirectory(String.format("%s/my-handler", __dirname))
        .runtime(CustomResourceProviderRuntime.NODEJS_22_X)
        .build());

String roleArn = provider.getRoleArn();
csharp
var provider = CustomResourceProvider.GetOrCreateProvider(this, "Custom::MyCustomResourceType", new CustomResourceProviderProps {
    CodeDirectory = $"{__dirname}/my-handler",
    Runtime = CustomResourceProviderRuntime.NODEJS_22_X
});

var roleArn = provider.RoleArn;
go
provider := awscdk.CustomResourceProvider_GetOrCreateProvider(this, jsii.String("Custom::MyCustomResourceType"), &CustomResourceProviderProps{
	CodeDirectory: fmt.Sprintf("%v/my-handler", __dirname),
	Runtime: awscdk.CustomResourceProviderRuntime_NODEJS_22_X,
})

roleArn := provider.roleArn

This role ARN can then be used in resource-based IAM policies.

To add IAM policy statements to this role, use addToRolePolicy():

ts
const provider = CustomResourceProvider.getOrCreateProvider(this, 'Custom::MyCustomResourceType', {
  codeDirectory: `${__dirname}/my-handler`,
  runtime: CustomResourceProviderRuntime.NODEJS_22_X,
});
provider.addToRolePolicy({
  Effect: 'Allow',
  Action: 's3:GetObject',
  Resource: '*',
})
python
provider = CustomResourceProvider.get_or_create_provider(self, "Custom::MyCustomResourceType",
    code_directory=f"{__dirname}/my-handler",
    runtime=CustomResourceProviderRuntime.NODEJS_22_X
)
provider.add_to_role_policy({
    "Effect": "Allow",
    "Action": "s3:GetObject",
    "Resource": "*"
})
java
CustomResourceProvider provider = CustomResourceProvider.getOrCreateProvider(this, "Custom::MyCustomResourceType", CustomResourceProviderProps.builder()
        .codeDirectory(String.format("%s/my-handler", __dirname))
        .runtime(CustomResourceProviderRuntime.NODEJS_22_X)
        .build());
provider.addToRolePolicy(Map.of(
        "Effect", "Allow",
        "Action", "s3:GetObject",
        "Resource", "*"));
csharp
var provider = CustomResourceProvider.GetOrCreateProvider(this, "Custom::MyCustomResourceType", new CustomResourceProviderProps {
    CodeDirectory = $"{__dirname}/my-handler",
    Runtime = CustomResourceProviderRuntime.NODEJS_22_X
});
provider.AddToRolePolicy(new Dictionary<string, string> {
    { "Effect", "Allow" },
    { "Action", "s3:GetObject" },
    { "Resource", "*" }
});
go
provider := awscdk.CustomResourceProvider_GetOrCreateProvider(this, jsii.String("Custom::MyCustomResourceType"), &CustomResourceProviderProps{
	CodeDirectory: fmt.Sprintf("%v/my-handler", __dirname),
	Runtime: awscdk.CustomResourceProviderRuntime_NODEJS_22_X,
})
provider.AddToRolePolicy(map[string]*string{
	"Effect": jsii.String("Allow"),
	"Action": jsii.String("s3:GetObject"),
	"Resource": jsii.String("*"),
})

Note that addToRolePolicy() uses direct IAM JSON policy blobs, not a iam.PolicyStatement object like you will see in the rest of the CDK.

The Custom Resource Provider Framework ​

The @aws-cdk/custom-resources module includes an advanced framework for implementing custom resource providers.

Handlers are implemented as AWS Lambda functions, which means that they can be implemented in any Lambda-supported runtime. Furthermore, this provider has an asynchronous mode, which means that users can provide an isComplete lambda function which is called periodically until the operation is complete. This allows implementing providers that can take up to two hours to stabilize.

Set serviceToken to provider.serviceToken to use this type of provider:

ts
const provider = new customresources.Provider(this, 'MyProvider', {
  onEventHandler,
  isCompleteHandler, // optional async waiter
});

new CustomResource(this, 'MyResource', {
  serviceToken: provider.serviceToken
});
python
provider = customresources.Provider(self, "MyProvider",
    on_event_handler=on_event_handler,
    is_complete_handler=is_complete_handler
)

CustomResource(self, "MyResource",
    service_token=provider.service_token
)
java
Provider provider = Provider.Builder.create(this, "MyProvider")
        .onEventHandler(onEventHandler)
        .isCompleteHandler(isCompleteHandler)
        .build();

CustomResource.Builder.create(this, "MyResource")
        .serviceToken(provider.getServiceToken())
        .build();
csharp
var provider = new Provider(this, "MyProvider", new ProviderProps {
    OnEventHandler = onEventHandler,
    IsCompleteHandler = isCompleteHandler
});

new CustomResource(this, "MyResource", new CustomResourceProps {
    ServiceToken = provider.ServiceToken
});
go
provider := customresources.NewProvider(this, jsii.String("MyProvider"), &ProviderProps{
	OnEventHandler: OnEventHandler,
	IsCompleteHandler: IsCompleteHandler,
})

awscdk.NewCustomResource(this, jsii.String("MyResource"), &CustomResourceProps{
	ServiceToken: provider.ServiceToken,
})

See the documentation for more details.

AWS CloudFormation features ​

A CDK stack synthesizes to an AWS CloudFormation Template. This section explains how this module allows users to access low-level CloudFormation features when needed.

Stack Outputs ​

CloudFormation stack outputs and exports are created using the CfnOutput class:

ts
new CfnOutput(this, 'OutputName', {
  value: myBucket.bucketName,
  description: 'The name of an S3 bucket', // Optional
  exportName: 'TheAwesomeBucket', // Registers a CloudFormation export named "TheAwesomeBucket"
});
python
CfnOutput(self, "OutputName",
    value=my_bucket.bucket_name,
    description="The name of an S3 bucket",  # Optional
    export_name="TheAwesomeBucket"
)
java
CfnOutput.Builder.create(this, "OutputName")
        .value(myBucket.getBucketName())
        .description("The name of an S3 bucket") // Optional
        .exportName("TheAwesomeBucket")
        .build();
csharp
new CfnOutput(this, "OutputName", new CfnOutputProps {
    Value = myBucket.BucketName,
    Description = "The name of an S3 bucket",  // Optional
    ExportName = "TheAwesomeBucket"
});
go
awscdk.NewCfnOutput(this, jsii.String("OutputName"), &CfnOutputProps{
	Value: myBucket.BucketName,
	Description: jsii.String("The name of an S3 bucket"),
	 // Optional
	ExportName: jsii.String("TheAwesomeBucket"),
})

You can also use the exportValue method to export values as stack outputs:

ts
declare const stack: Stack;

stack.exportValue(myBucket.bucketName, {
  name: 'TheAwesomeBucket',
  description: 'The name of an S3 bucket',
});
python
# stack: Stack


stack.export_value(my_bucket.bucket_name,
    name="TheAwesomeBucket",
    description="The name of an S3 bucket"
)
java
Stack stack;


stack.exportValue(myBucket.getBucketName(), ExportValueOptions.builder()
        .name("TheAwesomeBucket")
        .description("The name of an S3 bucket")
        .build());
csharp
Stack stack;


stack.ExportValue(myBucket.BucketName, new ExportValueOptions {
    Name = "TheAwesomeBucket",
    Description = "The name of an S3 bucket"
});
go
var stack Stack


stack.ExportValue(myBucket.BucketName, &ExportValueOptions{
	Name: jsii.String("TheAwesomeBucket"),
	Description: jsii.String("The name of an S3 bucket"),
})

Parameters ​

CloudFormation templates support the use of Parameters to customize a template. They enable CloudFormation users to input custom values to a template each time a stack is created or updated. While the CDK design philosophy favors using build-time parameterization, users may need to use CloudFormation in a number of cases (for example, when migrating an existing stack to the AWS CDK).

Template parameters can be added to a stack by using the CfnParameter class:

ts
new CfnParameter(this, 'MyParameter', {
  type: 'Number',
  default: 1337,
  // See the API reference for more configuration props
});
python
CfnParameter(self, "MyParameter",
    type="Number",
    default=1337
)
java
CfnParameter.Builder.create(this, "MyParameter")
        .type("Number")
        .default(1337)
        .build();
csharp
new CfnParameter(this, "MyParameter", new CfnParameterProps {
    Type = "Number",
    Default = 1337
});
go
awscdk.NewCfnParameter(this, jsii.String("MyParameter"), &CfnParameterProps{
	Type: jsii.String("Number"),
	Default: jsii.Number(1337),
})

The value of parameters can then be obtained using one of the value methods. As parameters are only resolved at deployment time, the values obtained are placeholder tokens for the real value (Token.isUnresolved() would return true for those):

ts
const param = new CfnParameter(this, 'ParameterName', { /* config */ });

// If the parameter is a String
param.valueAsString;

// If the parameter is a Number
param.valueAsNumber;

// If the parameter is a List
param.valueAsList;
python
param = CfnParameter(self, "ParameterName")

# If the parameter is a String
param.value_as_string

# If the parameter is a Number
param.value_as_number

# If the parameter is a List
param.value_as_list
java
CfnParameter param = CfnParameter.Builder.create(this, "ParameterName").build();

// If the parameter is a String
param.getValueAsString();

// If the parameter is a Number
param.getValueAsNumber();

// If the parameter is a List
param.getValueAsList();
csharp
var param = new CfnParameter(this, "ParameterName", new CfnParameterProps { });

// If the parameter is a String
param.ValueAsString;

// If the parameter is a Number
param.ValueAsNumber;

// If the parameter is a List
param.ValueAsList;
go
param := awscdk.NewCfnParameter(this, jsii.String("ParameterName"), &CfnParameterProps{
})

// If the parameter is a String
param.valueAsString

// If the parameter is a Number
param.valueAsNumber

// If the parameter is a List
param.valueAsList

Pseudo Parameters ​

CloudFormation supports a number of pseudo parameters, which resolve to useful values at deployment time. CloudFormation pseudo parameters can be obtained from static members of the Aws class.

It is generally recommended to access pseudo parameters from the scope's stack instead, which guarantees the values produced are qualifying the designated stack, which is essential in cases where resources are shared cross-stack:

ts
// "this" is the current construct
const stack = Stack.of(this);

stack.account; // Returns the AWS::AccountId for this stack (or the literal value if known)
stack.region;  // Returns the AWS::Region for this stack (or the literal value if known)
stack.partition; // Returns the AWS::Partition for this stack (or the literal value if known)
python
# "this" is the current construct
stack = Stack.of(self)

stack.account # Returns the AWS::AccountId for this stack (or the literal value if known)
stack.region # Returns the AWS::Region for this stack (or the literal value if known)
stack.partition
java
// "this" is the current construct
Stack stack = Stack.of(this);

stack.getAccount(); // Returns the AWS::AccountId for this stack (or the literal value if known)
stack.getRegion(); // Returns the AWS::Region for this stack (or the literal value if known)
stack.getPartition();
csharp
// "this" is the current construct
var stack = Stack.Of(this);

stack.Account; // Returns the AWS::AccountId for this stack (or the literal value if known)
stack.Region; // Returns the AWS::Region for this stack (or the literal value if known)
stack.Partition;
go
// "this" is the current construct
stack := awscdk.stack_Of(this)

stack.Account // Returns the AWS::AccountId for this stack (or the literal value if known)
stack.Region // Returns the AWS::Region for this stack (or the literal value if known)
stack.partition

Resource Options ​

CloudFormation resources can also specify resource attributes. The CfnResource class allows accessing those through the cfnOptions property:

ts
const rawBucket = new s3.CfnBucket(this, 'Bucket', { /* ... */ });
// -or-
const rawBucketAlt = myBucket.node.defaultChild as s3.CfnBucket;

// then
rawBucket.cfnOptions.condition = new CfnCondition(this, 'EnableBucket', { /* ... */ });
rawBucket.cfnOptions.metadata = {
  metadataKey: 'MetadataValue',
};
python
raw_bucket = s3.CfnBucket(self, "Bucket")
# -or-
raw_bucket_alt = my_bucket.node.default_child

# then
raw_bucket.cfn_options.condition = CfnCondition(self, "EnableBucket")
raw_bucket.cfn_options.metadata = {
    "metadata_key": "MetadataValue"
}
java
CfnBucket rawBucket = CfnBucket.Builder.create(this, "Bucket").build();
// -or-
CfnBucket rawBucketAlt = (CfnBucket)myBucket.getNode().getDefaultChild();

// then
rawBucket.getCfnOptions().getCondition() = CfnCondition.Builder.create(this, "EnableBucket").build();
rawBucket.getCfnOptions().getMetadata() = Map.of(
        "metadataKey", "MetadataValue");
csharp
var rawBucket = new CfnBucket(this, "Bucket", new CfnBucketProps { });
// -or-
var rawBucketAlt = (CfnBucket)myBucket.Node.DefaultChild;

// then
rawBucket.CfnOptions.Condition = new CfnCondition(this, "EnableBucket", new CfnConditionProps { });
rawBucket.CfnOptions.Metadata = new Dictionary<string, object> {
    { "metadataKey", "MetadataValue" }
};
go
rawBucket := s3.NewCfnBucket(this, jsii.String("Bucket"), &CfnBucketProps{
})
// -or-
rawBucketAlt := myBucket.Node.defaultChild.(CfnBucket)

// then
rawBucket.CfnOptions.Condition = awscdk.NewCfnCondition(this, jsii.String("EnableBucket"), &CfnConditionProps{
})
rawBucket.CfnOptions.Metadata = map[string]interface{}{
	"metadataKey": jsii.String("MetadataValue"),
}

Resource dependencies (the DependsOn attribute) is modified using the cfnResource.addDependency method:

ts
const resourceA = new CfnResource(this, 'ResourceA', resourceProps);
const resourceB = new CfnResource(this, 'ResourceB', resourceProps);

resourceB.addResourceDependency(resourceA);
python
resource_a = CfnResource(self, "ResourceA", resource_props)
resource_b = CfnResource(self, "ResourceB", resource_props)

resource_b.add_resource_dependency(resource_a)
java
CfnResource resourceA = new CfnResource(this, "ResourceA", resourceProps);
CfnResource resourceB = new CfnResource(this, "ResourceB", resourceProps);

resourceB.addResourceDependency(resourceA);
csharp
var resourceA = new CfnResource(this, "ResourceA", resourceProps);
var resourceB = new CfnResource(this, "ResourceB", resourceProps);

resourceB.AddResourceDependency(resourceA);
go
resourceA := awscdk.NewCfnResource(this, jsii.String("ResourceA"), resourceProps)
resourceB := awscdk.NewCfnResource(this, jsii.String("ResourceB"), resourceProps)

resourceB.AddResourceDependency(resourceA)

CreationPolicy ​

Some resources support a CreationPolicy to be specified as a CfnOption.

The creation policy is invoked only when AWS CloudFormation creates the associated resource. Currently, the only AWS CloudFormation resources that support creation policies are CfnAutoScalingGroup, CfnInstance, CfnWaitCondition and CfnFleet.

The CfnFleet resource from the aws-appstream module supports specifying startFleet as a property of the creationPolicy on the resource options. Setting it to true will make AWS CloudFormation wait until the fleet is started before continuing with the creation of resources that depend on the fleet resource.

ts
const fleet = new appstream.CfnFleet(this, 'Fleet', {
  instanceType: 'stream.standard.small',
  name: 'Fleet',
  computeCapacity: {
    desiredInstances: 1,
  },
  imageName: 'AppStream-AmazonLinux2-09-21-2022',
});
fleet.cfnOptions.creationPolicy = {
  startFleet: true,
};
python
from aws_cdk import CfnCreationPolicy
fleet = appstream.CfnFleet(self, "Fleet",
    instance_type="stream.standard.small",
    name="Fleet",
    compute_capacity=appstream.CfnFleet.ComputeCapacityProperty(
        desired_instances=1
    ),
    image_name="AppStream-AmazonLinux2-09-21-2022"
)
fleet.cfn_options.creation_policy = CfnCreationPolicy(
    start_fleet=True
)
java
CfnFleet fleet = CfnFleet.Builder.create(this, "Fleet")
        .instanceType("stream.standard.small")
        .name("Fleet")
        .computeCapacity(ComputeCapacityProperty.builder()
                .desiredInstances(1)
                .build())
        .imageName("AppStream-AmazonLinux2-09-21-2022")
        .build();
fleet.getCfnOptions().getCreationPolicy() = CfnCreationPolicy.builder()
        .startFleet(true)
        .build();
csharp
var fleet = new CfnFleet(this, "Fleet", new CfnFleetProps {
    InstanceType = "stream.standard.small",
    Name = "Fleet",
    ComputeCapacity = new ComputeCapacityProperty {
        DesiredInstances = 1
    },
    ImageName = "AppStream-AmazonLinux2-09-21-2022"
});
fleet.CfnOptions.CreationPolicy = new CfnCreationPolicy {
    StartFleet = true
};
go
fleet := appstream.NewCfnFleet(this, jsii.String("Fleet"), &CfnFleetProps{
	InstanceType: jsii.String("stream.standard.small"),
	Name: jsii.String("Fleet"),
	ComputeCapacity: &ComputeCapacityProperty{
		DesiredInstances: jsii.Number(1),
	},
	ImageName: jsii.String("AppStream-AmazonLinux2-09-21-2022"),
})
fleet.CfnOptions.CreationPolicy = &CfnCreationPolicy{
	StartFleet: jsii.Boolean(true),
}

The properties passed to the level 2 constructs AutoScalingGroup and Instance from the aws-ec2 module abstract what is passed into the CfnOption properties resourceSignal and autoScalingCreationPolicy, but when using level 1 constructs you can specify these yourself.

The CfnWaitCondition resource from the aws-cloudformation module supports the resourceSignal. The format of the timeout is PT#H#M#S. In the example below AWS Cloudformation will wait for 3 success signals to occur within 15 minutes before the status of the resource will be set to CREATE_COMPLETE.

ts
declare const resource: CfnResource;

resource.cfnOptions.creationPolicy = {
  resourceSignal: {
    count: 3,
    timeout: 'PR15M',
  }
};
python
from aws_cdk import CfnCreationPolicy, CfnResourceSignal
# resource: CfnResource


resource.cfn_options.creation_policy = CfnCreationPolicy(
    resource_signal=CfnResourceSignal(
        count=3,
        timeout="PR15M"
    )
)
java
CfnResource resource;


resource.getCfnOptions().getCreationPolicy() = CfnCreationPolicy.builder()
        .resourceSignal(CfnResourceSignal.builder()
                .count(3)
                .timeout("PR15M")
                .build())
        .build();
csharp
CfnResource resource;


resource.CfnOptions.CreationPolicy = new CfnCreationPolicy {
    ResourceSignal = new CfnResourceSignal {
        Count = 3,
        Timeout = "PR15M"
    }
};
go
var resource CfnResource


resource.CfnOptions.CreationPolicy = &CfnCreationPolicy{
	ResourceSignal: &CfnResourceSignal{
		Count: jsii.Number(3),
		Timeout: jsii.String("PR15M"),
	},
}

Intrinsic Functions and Condition Expressions ​

CloudFormation supports intrinsic functions. These functions can be accessed from the Fn class, which provides type-safe methods for each intrinsic function as well as condition expressions:

ts
declare const myObjectOrArray: any;
declare const myArray: any;

// To use Fn::Base64
Fn.base64('SGVsbG8gQ0RLIQo=');

// To compose condition expressions:
const environmentParameter = new CfnParameter(this, 'Environment');
Fn.conditionAnd(
  // The "Environment" CloudFormation template parameter evaluates to "Production"
  Fn.conditionEquals('Production', environmentParameter),
  // The AWS::Region pseudo-parameter value is NOT equal to "us-east-1"
  Fn.conditionNot(Fn.conditionEquals('us-east-1', Aws.REGION)),
);

// To use Fn::ToJsonString
Fn.toJsonString(myObjectOrArray);

// To use Fn::Length
Fn.len(Fn.split(',', myArray));
python
# my_object_or_array: Any
# my_array: Any


# To use Fn::Base64
Fn.base64("SGVsbG8gQ0RLIQo=")

# To compose condition expressions:
environment_parameter = CfnParameter(self, "Environment")
Fn.condition_and(
    # The "Environment" CloudFormation template parameter evaluates to "Production"
    Fn.condition_equals("Production", environment_parameter),
    # The AWS::Region pseudo-parameter value is NOT equal to "us-east-1"
    Fn.condition_not(Fn.condition_equals("us-east-1", Aws.REGION)))

# To use Fn::ToJsonString
Fn.to_json_string(my_object_or_array)

# To use Fn::Length
Fn.len(Fn.split(",", my_array))
java
Object myObjectOrArray;
Object myArray;


// To use Fn::Base64
Fn.base64("SGVsbG8gQ0RLIQo=");

// To compose condition expressions:
CfnParameter environmentParameter = new CfnParameter(this, "Environment");
Fn.conditionAnd(Fn.conditionEquals("Production", environmentParameter), Fn.conditionNot(Fn.conditionEquals("us-east-1", Aws.REGION)));

// To use Fn::ToJsonString
Fn.toJsonString(myObjectOrArray);

// To use Fn::Length
Fn.len(Fn.split(",", myArray));
csharp
var myObjectOrArray;
var myArray;


// To use Fn::Base64
Fn.Base64("SGVsbG8gQ0RLIQo=");

// To compose condition expressions:
var environmentParameter = new CfnParameter(this, "Environment");
Fn.ConditionAnd(Fn.ConditionEquals("Production", environmentParameter), Fn.ConditionNot(Fn.ConditionEquals("us-east-1", Aws.REGION)));

// To use Fn::ToJsonString
Fn.ToJsonString(myObjectOrArray);

// To use Fn::Length
Fn.Len(Fn.Split(",", myArray));
go
var myObjectOrArray interface{}
var myArray interface{}


// To use Fn::Base64
awscdk.Fn_Base64(jsii.String("SGVsbG8gQ0RLIQo="))

// To compose condition expressions:
environmentParameter := awscdk.NewCfnParameter(this, jsii.String("Environment"))
awscdk.Fn_ConditionAnd(awscdk.Fn_ConditionEquals(jsii.String("Production"), environmentParameter), awscdk.Fn_ConditionNot(awscdk.Fn_ConditionEquals(jsii.String("us-east-1"), awscdk.Aws_REGION())))

// To use Fn::ToJsonString
awscdk.Fn_ToJsonString(myObjectOrArray)

// To use Fn::Length
awscdk.Fn_Len(awscdk.Fn_Split(jsii.String(","), myArray))

When working with deploy-time values (those for which Token.isUnresolved returns true), idiomatic conditionals from the programming language cannot be used (the value will not be known until deployment time). When conditional logic needs to be expressed with un-resolved values, it is necessary to use CloudFormation conditions by means of the CfnCondition class:

ts
const environmentParameter = new CfnParameter(this, 'Environment');
const isProd = new CfnCondition(this, 'IsProduction', {
  expression: Fn.conditionEquals('Production', environmentParameter),
});

// Configuration value that is a different string based on IsProduction
const stage = Fn.conditionIf(isProd.logicalId, 'Beta', 'Prod').toString();

// Make Bucket creation condition to IsProduction by accessing
// and overriding the CloudFormation resource
const bucket = new s3.Bucket(this, 'Bucket');
const cfnBucket = myBucket.node.defaultChild as s3.CfnBucket;
cfnBucket.cfnOptions.condition = isProd;
python
environment_parameter = CfnParameter(self, "Environment")
is_prod = CfnCondition(self, "IsProduction",
    expression=Fn.condition_equals("Production", environment_parameter)
)

# Configuration value that is a different string based on IsProduction
stage = Fn.condition_if(is_prod.logical_id, "Beta", "Prod").to_string()

# Make Bucket creation condition to IsProduction by accessing
# and overriding the CloudFormation resource
bucket = s3.Bucket(self, "Bucket")
cfn_bucket = my_bucket.node.default_child
cfn_bucket.cfn_options.condition = is_prod
java
CfnParameter environmentParameter = new CfnParameter(this, "Environment");
CfnCondition isProd = CfnCondition.Builder.create(this, "IsProduction")
        .expression(Fn.conditionEquals("Production", environmentParameter))
        .build();

// Configuration value that is a different string based on IsProduction
String stage = Fn.conditionIf(isProd.logicalId, "Beta", "Prod").toString();

// Make Bucket creation condition to IsProduction by accessing
// and overriding the CloudFormation resource
Bucket bucket = new Bucket(this, "Bucket");
CfnBucket cfnBucket = (CfnBucket)myBucket.getNode().getDefaultChild();
cfnBucket.getCfnOptions().getCondition() = isProd;
csharp
var environmentParameter = new CfnParameter(this, "Environment");
var isProd = new CfnCondition(this, "IsProduction", new CfnConditionProps {
    Expression = Fn.ConditionEquals("Production", environmentParameter)
});

// Configuration value that is a different string based on IsProduction
var stage = Fn.ConditionIf(isProd.LogicalId, "Beta", "Prod").ToString();

// Make Bucket creation condition to IsProduction by accessing
// and overriding the CloudFormation resource
var bucket = new Bucket(this, "Bucket");
var cfnBucket = (CfnBucket)myBucket.Node.DefaultChild;
cfnBucket.CfnOptions.Condition = isProd;
go
environmentParameter := awscdk.NewCfnParameter(this, jsii.String("Environment"))
isProd := awscdk.NewCfnCondition(this, jsii.String("IsProduction"), &CfnConditionProps{
	Expression: awscdk.Fn_ConditionEquals(jsii.String("Production"), environmentParameter),
})

// Configuration value that is a different string based on IsProduction
stage := awscdk.Fn_ConditionIf(isProd.LogicalId, jsii.String("Beta"), jsii.String("Prod")).ToString()

// Make Bucket creation condition to IsProduction by accessing
// and overriding the CloudFormation resource
bucket := s3.NewBucket(this, jsii.String("Bucket"))
cfnBucket := myBucket.Node.defaultChild.(CfnBucket)
cfnBucket.CfnOptions.Condition = isProd

Mappings ​

CloudFormation mappings are created and queried using the CfnMappings class:

ts
const regionTable = new CfnMapping(this, 'RegionTable', {
  mapping: {
    'us-east-1': {
      regionName: 'US East (N. Virginia)',
      // ...
    },
    'us-east-2': {
      regionName: 'US East (Ohio)',
      // ...
    },
    // ...
  }
});

regionTable.findInMap(Aws.REGION, 'regionName')
python
region_table = CfnMapping(self, "RegionTable",
    mapping={
        "us-east-1": {
            "region_name": "US East (N. Virginia)"
        },
        "us-east-2": {
            "region_name": "US East (Ohio)"
        }
    }
)

region_table.find_in_map(Aws.REGION, "regionName")
java
CfnMapping regionTable = CfnMapping.Builder.create(this, "RegionTable")
        .mapping(Map.of(
                "us-east-1", Map.of(
                        "regionName", "US East (N. Virginia)"),
                "us-east-2", Map.of(
                        "regionName", "US East (Ohio)")))
        .build();

regionTable.findInMap(Aws.REGION, "regionName");
csharp
var regionTable = new CfnMapping(this, "RegionTable", new CfnMappingProps {
    Mapping = new Dictionary<string, IDictionary<string, object>> {
        { "us-east-1", new Dictionary<string, object> {
            { "regionName", "US East (N. Virginia)" }
        } },
        { "us-east-2", new Dictionary<string, object> {
            { "regionName", "US East (Ohio)" }
        } }
    }
});

regionTable.FindInMap(Aws.REGION, "regionName");
go
regionTable := awscdk.NewCfnMapping(this, jsii.String("RegionTable"), &CfnMappingProps{
	Mapping: map[string]map[string]interface{}{
		"us-east-1": map[string]interface{}{
			"regionName": jsii.String("US East (N. Virginia)"),
		},
		"us-east-2": map[string]interface{}{
			"regionName": jsii.String("US East (Ohio)"),
		},
	},
})

regionTable.FindInMap(awscdk.Aws_REGION(), jsii.String("regionName"))

This will yield the following template:

yaml
Mappings:
  RegionTable:
    us-east-1:
      regionName: US East (N. Virginia)
    us-east-2:
      regionName: US East (Ohio)

Mappings can also be synthesized "lazily"; lazy mappings will only render a "Mappings" section in the synthesized CloudFormation template if some findInMap call is unable to immediately return a concrete value due to one or both of the keys being unresolved tokens (some value only available at deploy-time).

For example, the following code will not produce anything in the "Mappings" section. The call to findInMap will be able to resolve the value during synthesis and simply return 'US East (Ohio)'.

ts
const regionTable = new CfnMapping(this, 'RegionTable', {
  mapping: {
    'us-east-1': {
      regionName: 'US East (N. Virginia)',
    },
    'us-east-2': {
      regionName: 'US East (Ohio)',
    },
  },
  lazy: true,
});

regionTable.findInMap('us-east-2', 'regionName');
python
region_table = CfnMapping(self, "RegionTable",
    mapping={
        "us-east-1": {
            "region_name": "US East (N. Virginia)"
        },
        "us-east-2": {
            "region_name": "US East (Ohio)"
        }
    },
    lazy=True
)

region_table.find_in_map("us-east-2", "regionName")
java
CfnMapping regionTable = CfnMapping.Builder.create(this, "RegionTable")
        .mapping(Map.of(
                "us-east-1", Map.of(
                        "regionName", "US East (N. Virginia)"),
                "us-east-2", Map.of(
                        "regionName", "US East (Ohio)")))
        .lazy(true)
        .build();

regionTable.findInMap("us-east-2", "regionName");
csharp
var regionTable = new CfnMapping(this, "RegionTable", new CfnMappingProps {
    Mapping = new Dictionary<string, IDictionary<string, object>> {
        { "us-east-1", new Dictionary<string, object> {
            { "regionName", "US East (N. Virginia)" }
        } },
        { "us-east-2", new Dictionary<string, object> {
            { "regionName", "US East (Ohio)" }
        } }
    },
    Lazy = true
});

regionTable.FindInMap("us-east-2", "regionName");
go
regionTable := awscdk.NewCfnMapping(this, jsii.String("RegionTable"), &CfnMappingProps{
	Mapping: map[string]map[string]interface{}{
		"us-east-1": map[string]interface{}{
			"regionName": jsii.String("US East (N. Virginia)"),
		},
		"us-east-2": map[string]interface{}{
			"regionName": jsii.String("US East (Ohio)"),
		},
	},
	Lazy: jsii.Boolean(true),
})

regionTable.FindInMap(jsii.String("us-east-2"), jsii.String("regionName"))

On the other hand, the following code will produce the "Mappings" section shown above, since the top-level key is an unresolved token. The call to findInMap will return a token that resolves to { "Fn::FindInMap": [ "RegionTable", { "Ref": "AWS::Region" }, "regionName" ] }.

ts
declare const regionTable: CfnMapping;

regionTable.findInMap(Aws.REGION, 'regionName');
python
# region_table: CfnMapping


region_table.find_in_map(Aws.REGION, "regionName")
java
CfnMapping regionTable;


regionTable.findInMap(Aws.REGION, "regionName");
csharp
CfnMapping regionTable;


regionTable.FindInMap(Aws.REGION, "regionName");
go
var regionTable CfnMapping


regionTable.FindInMap(awscdk.Aws_REGION(), jsii.String("regionName"))

An optional default value can also be passed to findInMap. If either key is not found in the map and the mapping is lazy, findInMap will return the default value and not render the mapping. If the mapping is not lazy or either key is an unresolved token, the call to findInMap will return a token that resolves to { "Fn::FindInMap": [ "MapName", "TopLevelKey", "SecondLevelKey", { "DefaultValue": "DefaultValue" } ] }, and the mapping will be rendered. Note that the AWS::LanguageExtentions transform is added to enable the default value functionality.

For example, the following code will again not produce anything in the "Mappings" section. The call to findInMap will be able to resolve the value during synthesis and simply return 'Region not found'.

ts
const regionTable = new CfnMapping(this, 'RegionTable', {
  mapping: {
    'us-east-1': {
      regionName: 'US East (N. Virginia)',
    },
    'us-east-2': {
      regionName: 'US East (Ohio)',
    },
  },
  lazy: true,
});

regionTable.findInMap('us-west-1', 'regionName', 'Region not found');
python
region_table = CfnMapping(self, "RegionTable",
    mapping={
        "us-east-1": {
            "region_name": "US East (N. Virginia)"
        },
        "us-east-2": {
            "region_name": "US East (Ohio)"
        }
    },
    lazy=True
)

region_table.find_in_map("us-west-1", "regionName", "Region not found")
java
CfnMapping regionTable = CfnMapping.Builder.create(this, "RegionTable")
        .mapping(Map.of(
                "us-east-1", Map.of(
                        "regionName", "US East (N. Virginia)"),
                "us-east-2", Map.of(
                        "regionName", "US East (Ohio)")))
        .lazy(true)
        .build();

regionTable.findInMap("us-west-1", "regionName", "Region not found");
csharp
var regionTable = new CfnMapping(this, "RegionTable", new CfnMappingProps {
    Mapping = new Dictionary<string, IDictionary<string, object>> {
        { "us-east-1", new Dictionary<string, object> {
            { "regionName", "US East (N. Virginia)" }
        } },
        { "us-east-2", new Dictionary<string, object> {
            { "regionName", "US East (Ohio)" }
        } }
    },
    Lazy = true
});

regionTable.FindInMap("us-west-1", "regionName", "Region not found");
go
regionTable := awscdk.NewCfnMapping(this, jsii.String("RegionTable"), &CfnMappingProps{
	Mapping: map[string]map[string]interface{}{
		"us-east-1": map[string]interface{}{
			"regionName": jsii.String("US East (N. Virginia)"),
		},
		"us-east-2": map[string]interface{}{
			"regionName": jsii.String("US East (Ohio)"),
		},
	},
	Lazy: jsii.Boolean(true),
})

regionTable.FindInMap(jsii.String("us-west-1"), jsii.String("regionName"), jsii.String("Region not found"))

Dynamic References ​

CloudFormation supports dynamically resolving values for SSM parameters (including secure strings) and Secrets Manager. Encoding such references is done using the CfnDynamicReference class:

ts
new CfnDynamicReference(
  CfnDynamicReferenceService.SECRETS_MANAGER,
  'secret-id:secret-string:json-key:version-stage:version-id',
);
python
CfnDynamicReference(CfnDynamicReferenceService.SECRETS_MANAGER, "secret-id:secret-string:json-key:version-stage:version-id")
java
new CfnDynamicReference(CfnDynamicReferenceService.SECRETS_MANAGER, "secret-id:secret-string:json-key:version-stage:version-id");
csharp
new CfnDynamicReference(CfnDynamicReferenceService.SECRETS_MANAGER, "secret-id:secret-string:json-key:version-stage:version-id");
go
awscdk.NewCfnDynamicReference(awscdk.CfnDynamicReferenceService_SECRETS_MANAGER, jsii.String("secret-id:secret-string:json-key:version-stage:version-id"))

RemovalPolicies ​

The RemovalPolicies class provides a convenient way to manage removal policies for AWS CDK resources within a construct scope. It allows you to apply removal policies to multiple resources at once, with options to include or exclude specific resource types.

ts
declare const scope: Construct;
declare const parent: Construct;
declare const bucket: s3.CfnBucket;

// Apply DESTROY policy to all resources in a scope
RemovalPolicies.of(scope).destroy();

// Apply RETAIN policy to all resources in a scope
RemovalPolicies.of(scope).retain();

// Apply SNAPSHOT policy to all resources in a scope
RemovalPolicies.of(scope).snapshot();

// Apply RETAIN_ON_UPDATE_OR_DELETE policy to all resources in a scope
RemovalPolicies.of(scope).retainOnUpdateOrDelete();

// Apply RETAIN policy only to specific resource types
RemovalPolicies.of(parent).retain({
  applyToResourceTypes: [
    'AWS::DynamoDB::Table',
    bucket.cfnResourceType, // 'AWS::S3::Bucket'
    rds.CfnDBInstance.CFN_RESOURCE_TYPE_NAME, // 'AWS::RDS::DBInstance'
  ],
});

// Apply SNAPSHOT policy excluding specific resource types
RemovalPolicies.of(scope).snapshot({
  excludeResourceTypes: ['AWS::Test::Resource'],
});
python
# scope: Construct
# parent: Construct
# bucket: s3.CfnBucket


# Apply DESTROY policy to all resources in a scope
RemovalPolicies.of(scope).destroy()

# Apply RETAIN policy to all resources in a scope
RemovalPolicies.of(scope).retain()

# Apply SNAPSHOT policy to all resources in a scope
RemovalPolicies.of(scope).snapshot()

# Apply RETAIN_ON_UPDATE_OR_DELETE policy to all resources in a scope
RemovalPolicies.of(scope).retain_on_update_or_delete()

# Apply RETAIN policy only to specific resource types
RemovalPolicies.of(parent).retain(
    apply_to_resource_types=["AWS::DynamoDB::Table", bucket.cfn_resource_type, rds.CfnDBInstance.CFN_RESOURCE_TYPE_NAME
    ]
)

# Apply SNAPSHOT policy excluding specific resource types
RemovalPolicies.of(scope).snapshot(
    exclude_resource_types=["AWS::Test::Resource"]
)
java
Construct scope;
Construct parent;
CfnBucket bucket;


// Apply DESTROY policy to all resources in a scope
RemovalPolicies.of(scope).destroy();

// Apply RETAIN policy to all resources in a scope
RemovalPolicies.of(scope).retain();

// Apply SNAPSHOT policy to all resources in a scope
RemovalPolicies.of(scope).snapshot();

// Apply RETAIN_ON_UPDATE_OR_DELETE policy to all resources in a scope
RemovalPolicies.of(scope).retainOnUpdateOrDelete();

// Apply RETAIN policy only to specific resource types
RemovalPolicies.of(parent).retain(RemovalPolicyProps.builder()
        .applyToResourceTypes(List.of("AWS::DynamoDB::Table", bucket.getCfnResourceType(), CfnDBInstance.CFN_RESOURCE_TYPE_NAME))
        .build());

// Apply SNAPSHOT policy excluding specific resource types
RemovalPolicies.of(scope).snapshot(RemovalPolicyProps.builder()
        .excludeResourceTypes(List.of("AWS::Test::Resource"))
        .build());
csharp
Construct scope;
Construct parent;
CfnBucket bucket;


// Apply DESTROY policy to all resources in a scope
RemovalPolicies.Of(scope).Destroy();

// Apply RETAIN policy to all resources in a scope
RemovalPolicies.Of(scope).Retain();

// Apply SNAPSHOT policy to all resources in a scope
RemovalPolicies.Of(scope).Snapshot();

// Apply RETAIN_ON_UPDATE_OR_DELETE policy to all resources in a scope
RemovalPolicies.Of(scope).RetainOnUpdateOrDelete();

// Apply RETAIN policy only to specific resource types
RemovalPolicies.Of(parent).Retain(new RemovalPolicyProps {
    ApplyToResourceTypes = new [] { "AWS::DynamoDB::Table", bucket.CfnResourceType, CfnDBInstance.CFN_RESOURCE_TYPE_NAME }
});

// Apply SNAPSHOT policy excluding specific resource types
RemovalPolicies.Of(scope).Snapshot(new RemovalPolicyProps {
    ExcludeResourceTypes = new [] { "AWS::Test::Resource" }
});
go
var scope Construct
var parent Construct
var bucket CfnBucket


// Apply DESTROY policy to all resources in a scope
awscdk.RemovalPolicies_Of(*scope).Destroy()

// Apply RETAIN policy to all resources in a scope
awscdk.RemovalPolicies_Of(*scope).Retain()

// Apply SNAPSHOT policy to all resources in a scope
awscdk.RemovalPolicies_Of(*scope).Snapshot()

// Apply RETAIN_ON_UPDATE_OR_DELETE policy to all resources in a scope
awscdk.RemovalPolicies_Of(*scope).RetainOnUpdateOrDelete()

// Apply RETAIN policy only to specific resource types
awscdk.RemovalPolicies_Of(parent).Retain(&RemovalPolicyProps{
	ApplyToResourceTypes: []*string{
		jsii.String("AWS::DynamoDB::Table"),
		bucket.CfnResourceType,
		rds.CfnDBInstance_CFN_RESOURCE_TYPE_NAME(),
	},
})

// Apply SNAPSHOT policy excluding specific resource types
awscdk.RemovalPolicies_Of(*scope).Snapshot(&RemovalPolicyProps{
	ExcludeResourceTypes: []*string{
		jsii.String("AWS::Test::Resource"),
	},
})

RemovalPolicies vs MissingRemovalPolicies ​

CDK provides two different classes for managing removal policies:

  • RemovalPolicies: Always applies the specified removal policy, overriding any existing policies.
  • MissingRemovalPolicies: Applies the removal policy only to resources that don't already have a policy set.
ts
// Override any existing policies
RemovalPolicies.of(scope).retain();

// Only apply to resources without existing policies
MissingRemovalPolicies.of(scope).retain();
python
# Override any existing policies
RemovalPolicies.of(scope).retain()

# Only apply to resources without existing policies
MissingRemovalPolicies.of(scope).retain()
java
// Override any existing policies
RemovalPolicies.of(scope).retain();

// Only apply to resources without existing policies
MissingRemovalPolicies.of(scope).retain();
csharp
// Override any existing policies
RemovalPolicies.Of(scope).Retain();

// Only apply to resources without existing policies
MissingRemovalPolicies.Of(scope).Retain();
go
// Override any existing policies
awscdk.RemovalPolicies_Of(*scope).Retain()

// Only apply to resources without existing policies
awscdk.MissingRemovalPolicies_Of(*scope).Retain()

Aspect Priority ​

Both RemovalPolicies and MissingRemovalPolicies are implemented as Aspects. You can control the order in which they're applied using the priority parameter:

ts
declare const stack: Stack;

// Apply in a specific order based on priority
RemovalPolicies.of(stack).retain({ priority: 100 });
RemovalPolicies.of(stack).destroy({ priority: 200 }); // This will override the RETAIN policy
python
# stack: Stack


# Apply in a specific order based on priority
RemovalPolicies.of(stack).retain(priority=100)
RemovalPolicies.of(stack).destroy(priority=200)
java
Stack stack;


// Apply in a specific order based on priority
RemovalPolicies.of(stack).retain(RemovalPolicyProps.builder().priority(100).build());
RemovalPolicies.of(stack).destroy(RemovalPolicyProps.builder().priority(200).build());
csharp
Stack stack;


// Apply in a specific order based on priority
RemovalPolicies.Of(stack).Retain(new RemovalPolicyProps { Priority = 100 });
RemovalPolicies.Of(stack).Destroy(new RemovalPolicyProps { Priority = 200 });
go
var stack Stack


// Apply in a specific order based on priority
awscdk.RemovalPolicies_Of(stack).Retain(&RemovalPolicyProps{
	Priority: jsii.Number(100),
})
awscdk.RemovalPolicies_Of(stack).Destroy(&RemovalPolicyProps{
	Priority: jsii.Number(200),
})

For RemovalPolicies, the policies are applied in order of aspect execution, with the last applied policy overriding previous ones. The priority only affects the order in which aspects are applied during synthesis.

Note ​

When using MissingRemovalPolicies with priority, a warning will be issued as this can lead to unexpected behavior. This is because MissingRemovalPolicies only applies to resources without existing policies, making priority less relevant.

Template Options & Transform ​

CloudFormation templates support a number of options, including which Macros or Transforms to use when deploying the stack. Those can be configured using the stack.templateOptions property:

ts
const stack = new Stack(app, 'StackName');

stack.templateOptions.description = 'This will appear in the AWS console';
stack.templateOptions.transforms = ['AWS::Serverless-2016-10-31'];
stack.templateOptions.metadata = {
  metadataKey: 'MetadataValue',
};
python
stack = Stack(app, "StackName")

stack.template_options.description = "This will appear in the AWS console"
stack.template_options.transforms = ["AWS::Serverless-2016-10-31"]
stack.template_options.metadata = {
    "metadata_key": "MetadataValue"
}
java
Stack stack = new Stack(app, "StackName");

stack.getTemplateOptions().getDescription() = "This will appear in the AWS console";
stack.getTemplateOptions().getTransforms() = List.of("AWS::Serverless-2016-10-31");
stack.getTemplateOptions().getMetadata() = Map.of(
        "metadataKey", "MetadataValue");
csharp
var stack = new Stack(app, "StackName");

stack.TemplateOptions.Description = "This will appear in the AWS console";
stack.TemplateOptions.Transforms = new [] { "AWS::Serverless-2016-10-31" };
stack.TemplateOptions.Metadata = new Dictionary<string, object> {
    { "metadataKey", "MetadataValue" }
};
go
stack := awscdk.Newstack(app, jsii.String("StackName"))

stack.TemplateOptions.Description = "This will appear in the AWS console"
stack.TemplateOptions.Transforms = []*string{
	"AWS::Serverless-2016-10-31",
}
stack.TemplateOptions.Metadata = map[string]interface{}{
	"metadataKey": jsii.String("MetadataValue"),
}

Emitting Raw Resources ​

The CfnResource class allows emitting arbitrary entries in the Resources section of the CloudFormation template.

ts
new CfnResource(this, 'ResourceId', {
  type: 'AWS::S3::Bucket',
  properties: {
    BucketName: 'amzn-s3-demo-bucket'
  },
});
python
CfnResource(self, "ResourceId",
    type="AWS::S3::Bucket",
    properties={
        "BucketName": "amzn-s3-demo-bucket"
    }
)
java
CfnResource.Builder.create(this, "ResourceId")
        .type("AWS::S3::Bucket")
        .properties(Map.of(
                "BucketName", "amzn-s3-demo-bucket"))
        .build();
csharp
new CfnResource(this, "ResourceId", new CfnResourceProps {
    Type = "AWS::S3::Bucket",
    Properties = new Dictionary<string, object> {
        { "BucketName", "amzn-s3-demo-bucket" }
    }
});
go
awscdk.NewCfnResource(this, jsii.String("ResourceId"), &CfnResourceProps{
	Type: jsii.String("AWS::S3::Bucket"),
	Properties: map[string]interface{}{
		"BucketName": jsii.String("amzn-s3-demo-bucket"),
	},
})

As for any other resource, the logical ID in the CloudFormation template will be generated by the AWS CDK, but the type and properties will be copied verbatim in the synthesized template.

Including raw CloudFormation template fragments ​

When migrating a CloudFormation stack to the AWS CDK, it can be useful to include fragments of an existing template verbatim in the synthesized template. This can be achieved using the CfnInclude class.

ts
new CfnInclude(this, 'ID', {
  template: {
    Resources: {
      Bucket: {
        Type: 'AWS::S3::Bucket',
        Properties: {
          BucketName: 'amzn-s3-demo-bucket'
        }
      }
    }
  },
});
python
CfnInclude(self, "ID",
    template={
        "Resources": {
            "Bucket": {
                "Type": "AWS::S3::Bucket",
                "Properties": {
                    "BucketName": "amzn-s3-demo-bucket"
                }
            }
        }
    }
)
java
new CfnInclude(this, "ID", new CfnIncludeProps()
        .template(Map.of(
                "Resources", Map.of(
                        "Bucket", Map.of(
                                "Type", "AWS::S3::Bucket",
                                "Properties", Map.of(
                                        "BucketName", "amzn-s3-demo-bucket")))))
        );
csharp
new CfnInclude(this, "ID", new CfnIncludeProps {
    Template = new Dictionary<string, IDictionary<string, IDictionary<string, object>>> {
        { "Resources", new Struct {
            Bucket = new Struct {
                Type = "AWS::S3::Bucket",
                Properties = new Struct {
                    BucketName = "amzn-s3-demo-bucket"
                }
            }
        } }
    }
});
go
awscdk.NewCfnInclude(this, jsii.String("ID"), &CfnIncludeProps{
	template: map[string]map[string]map[string]interface{}{
		"Resources": map[string]map[string]interface{}{
			"Bucket": map[string]interface{}{
				"Type": jsii.String("AWS::S3::Bucket"),
				"Properties": map[string]*string{
					"BucketName": jsii.String("amzn-s3-demo-bucket"),
				},
			},
		},
	},
})

Termination Protection ​

You can prevent a stack from being accidentally deleted by enabling termination protection on the stack. If a user attempts to delete a stack with termination protection enabled, the deletion fails and the stack--including its status--remains unchanged. Enabling or disabling termination protection on a stack sets it for any nested stacks belonging to that stack as well. You can enable termination protection on a stack by setting the terminationProtection prop to true.

ts
const stack = new Stack(app, 'StackName', {
  terminationProtection: true,
});
python
stack = Stack(app, "StackName",
    termination_protection=True
)
java
Stack stack = Stack.Builder.create(app, "StackName")
        .terminationProtection(true)
        .build();
csharp
var stack = new Stack(app, "StackName", new StackProps {
    TerminationProtection = true
});
go
stack := awscdk.Newstack(app, jsii.String("StackName"), &StackProps{
	TerminationProtection: jsii.Boolean(true),
})

You can also set termination protection with the setter after you've instantiated the stack.

ts
const stack = new Stack(app, 'StackName', {});
stack.terminationProtection = true;
python
stack = Stack(app, "StackName")
stack.termination_protection = True
java
Stack stack = Stack.Builder.create(app, "StackName").build();
stack.getTerminationProtection() = true;
csharp
var stack = new Stack(app, "StackName", new StackProps { });
stack.TerminationProtection = true;
go
stack := awscdk.Newstack(app, jsii.String("StackName"), &StackProps{
})
stack.terminationProtection = true

By default, termination protection is disabled.

Description ​

You can add a description of the stack in the same way as StackProps.

ts
const stack = new Stack(app, 'StackName', {
  description: 'This is a description.',
});
python
stack = Stack(app, "StackName",
    description="This is a description."
)
java
Stack stack = Stack.Builder.create(app, "StackName")
        .description("This is a description.")
        .build();
csharp
var stack = new Stack(app, "StackName", new StackProps {
    Description = "This is a description."
});
go
stack := awscdk.Newstack(app, jsii.String("StackName"), &StackProps{
	Description: jsii.String("This is a description."),
})

Receiving CloudFormation Stack Events ​

You can add one or more SNS Topic ARNs to any Stack:

ts
const stack = new Stack(app, 'StackName', {
  notificationArns: ['arn:aws:sns:us-east-1:123456789012:Topic'],
});
python
stack = Stack(app, "StackName",
    notification_arns=["arn:aws:sns:us-east-1:123456789012:Topic"]
)
java
Stack stack = Stack.Builder.create(app, "StackName")
        .notificationArns(List.of("arn:aws:sns:us-east-1:123456789012:Topic"))
        .build();
csharp
var stack = new Stack(app, "StackName", new StackProps {
    NotificationArns = new [] { "arn:aws:sns:us-east-1:123456789012:Topic" }
});
go
stack := awscdk.Newstack(app, jsii.String("StackName"), &StackProps{
	NotificationArns: []*string{
		jsii.String("arn:aws:sns:us-east-1:123456789012:Topic"),
	},
})

Stack events will be sent to any SNS Topics in this list. These ARNs are added to those specified using the --notification-arns command line option.

Note that in order to do delete notification ARNs entirely, you must pass an empty array ([]) instead of omitting it. If you omit the property, no action on existing ARNs will take place.

NOTE

Adding the notificationArns property (or using the --notification-arns CLI options) will override any existing ARNs configured on the stack. If you have an external system managing notification ARNs, either migrate to use this mechanism, or avoid specfying notification ARNs with the CDK.

CfnJson ​

CfnJson allows you to postpone the resolution of a JSON blob from deployment-time. This is useful in cases where the CloudFormation JSON template cannot express a certain value.

A common example is to use CfnJson in order to render a JSON map which needs to use intrinsic functions in keys. Since JSON map keys must be strings, it is impossible to use intrinsics in keys and CfnJson can help.

The following example defines an IAM role which can only be assumed by principals that are tagged with a specific tag.

ts
const tagParam = new CfnParameter(this, 'TagName');

const stringEquals = new CfnJson(this, 'ConditionJson', {
  value: {
    [`aws:PrincipalTag/${tagParam.valueAsString}`]: true,
  },
});

const principal = new iam.AccountRootPrincipal().withConditions({
  StringEquals: stringEquals,
});

new iam.Role(this, 'MyRole', { assumedBy: principal });
python
tag_param = CfnParameter(self, "TagName")

string_equals = CfnJson(self, "ConditionJson",
    value={
        "f"aws:PrincipalTag/{tagParam.valueAsString}"": True
    }
)

principal = iam.AccountRootPrincipal().with_conditions({
    "StringEquals": string_equals
})

iam.Role(self, "MyRole", assumed_by=principal)
java
CfnParameter tagParam = new CfnParameter(this, "TagName");

CfnJson stringEquals = CfnJson.Builder.create(this, "ConditionJson")
        .value(Map.of(
                String.format("aws:PrincipalTag/%s", tagParam.getValueAsString()), true))
        .build();

PrincipalBase principal = new AccountRootPrincipal().withConditions(Map.of(
        "StringEquals", stringEquals));

Role.Builder.create(this, "MyRole").assumedBy(principal).build();
csharp
var tagParam = new CfnParameter(this, "TagName");

var stringEquals = new CfnJson(this, "ConditionJson", new CfnJsonProps {
    Value = new Dictionary<string, boolean> {
        { $"aws:PrincipalTag/{tagParam.valueAsString}", true }
    }
});

var principal = new AccountRootPrincipal().WithConditions(new Dictionary<string, object> {
    { "StringEquals", stringEquals }
});

new Role(this, "MyRole", new RoleProps { AssumedBy = principal });
go
tagParam := awscdk.NewCfnParameter(this, jsii.String("TagName"))

stringEquals := awscdk.NewCfnJson(this, jsii.String("ConditionJson"), &CfnJsonProps{
	Value: map[string]*bool{
		fmt.Sprintf("aws:PrincipalTag/%v", tagParam.valueAsString): jsii.Boolean(true),
	},
})

principal := iam.NewAccountRootPrincipal().WithConditions(map[string]interface{}{
	"StringEquals": stringEquals,
})

iam.NewRole(this, jsii.String("MyRole"), &RoleProps{
	AssumedBy: principal,
})

Explanation: since in this example we pass the tag name through a parameter, it can only be resolved during deployment. The resolved value can be represented in the template through a { "Ref": "TagName" }. However, since we want to use this value inside a aws:PrincipalTag/TAG-NAME IAM operator, we need it in the key of a StringEquals condition. JSON keys must be strings, so to circumvent this limitation, we use CfnJson to "delay" the rendition of this template section to deploy-time. This means that the value of StringEquals in the template will be { "Fn::GetAtt": [ "ConditionJson", "Value" ] }, and will only "expand" to the operator we synthesized during deployment.

Stack Resource Limit ​

When deploying to AWS CloudFormation, it needs to keep in check the amount of resources being added inside a Stack. Currently it's possible to check the limits in the AWS CloudFormation quotas page.

It's possible to synthesize the project with more Resources than the allowed (or even reduce the number of Resources).

Set the context key @aws-cdk/core:stackResourceLimit with the proper value, being 0 for disable the limit of resources.

Template Indentation ​

The AWS CloudFormation templates generated by CDK include indentation by default. Indentation makes the templates more readable, but also increases their size, and CloudFormation templates cannot exceed 1MB.

It's possible to reduce the size of your templates by suppressing indentation.

To do this for all templates, set the context key @aws-cdk/core:suppressTemplateIndentation to true.

To do this for a specific stack, add a suppressTemplateIndentation: true property to the stack's StackProps parameter. You can also set this property to false to override the context key setting.

Similarly, to do this for a specific nested stack, add a suppressTemplateIndentation: true property to its NestedStackProps parameter. You can also set this property to false to override the context key setting.

App Context ​

Context values are key-value pairs that can be associated with an app, stack, or construct. One common use case for context is to use it for enabling/disabling feature flags. There are several places where context can be specified. They are listed below in the order they are evaluated (items at the top take precedence over those below).

  • The node.setContext() method
  • The postCliContext prop when you create an App
  • The CLI via the --context CLI argument
  • The cdk.json file via the context key:
  • The cdk.context.json file:
  • The ~/.cdk.json file via the context key:
  • The context prop when you create an App

Examples of setting context ​

ts
new App({
  context: {
    '@aws-cdk/core:newStyleStackSynthesis': true,
  },
});
python
App(
    context={
        "@aws-cdk/core:newStyleStackSynthesis": True
    }
)
java
App.Builder.create()
        .context(Map.of(
                "@aws-cdk/core:newStyleStackSynthesis", true))
        .build();
csharp
new App(new AppProps {
    Context = new Dictionary<string, object> {
        { "@aws-cdk/core:newStyleStackSynthesis", true }
    }
});
go
awscdk.NewApp(&AppProps{
	Context: map[string]interface{}{
		"@aws-cdk/core:newStyleStackSynthesis": jsii.Boolean(true),
	},
})
ts
const app = new App();
app.node.setContext('@aws-cdk/core:newStyleStackSynthesis', true);
python
app = App()
app.node.set_context("@aws-cdk/core:newStyleStackSynthesis", True)
java
App app = new App();
app.node.setContext("@aws-cdk/core:newStyleStackSynthesis", true);
csharp
var app = new App();
app.Node.SetContext("@aws-cdk/core:newStyleStackSynthesis", true);
go
app := awscdk.NewApp()
app.Node.SetContext(jsii.String("@aws-cdk/core:newStyleStackSynthesis"), jsii.Boolean(true))
ts
new App({
  postCliContext: {
    '@aws-cdk/core:newStyleStackSynthesis': true,
  },
});
python
App(
    post_cli_context={
        "@aws-cdk/core:newStyleStackSynthesis": True
    }
)
java
App.Builder.create()
        .postCliContext(Map.of(
                "@aws-cdk/core:newStyleStackSynthesis", true))
        .build();
csharp
new App(new AppProps {
    PostCliContext = new Dictionary<string, object> {
        { "@aws-cdk/core:newStyleStackSynthesis", true }
    }
});
go
awscdk.NewApp(&AppProps{
	PostCliContext: map[string]interface{}{
		"@aws-cdk/core:newStyleStackSynthesis": jsii.Boolean(true),
	},
})
console
cdk synth --context @aws-cdk/core:newStyleStackSynthesis=true

cdk.json ​

json
{
  "context": {
    "@aws-cdk/core:newStyleStackSynthesis": true
  }
}

cdk.context.json ​

json
{
  "@aws-cdk/core:newStyleStackSynthesis": true
}

~/.cdk.json ​

json
{
  "context": {
    "@aws-cdk/core:newStyleStackSynthesis": true
  }
}

IAM Permissions Boundary ​

It is possible to apply an IAM permissions boundary to all roles within a specific construct scope. The most common use case would be to apply a permissions boundary at the Stage level.

ts
const prodStage = new Stage(app, 'ProdStage', {
  permissionsBoundary: PermissionsBoundary.fromName('cdk-${Qualifier}-PermissionsBoundary'),
});
python
prod_stage = Stage(app, "ProdStage",
    permissions_boundary=PermissionsBoundary.from_name("cdk-${Qualifier}-PermissionsBoundary")
)
java
Stage prodStage = Stage.Builder.create(app, "ProdStage")
        .permissionsBoundary(PermissionsBoundary.fromName("cdk-${Qualifier}-PermissionsBoundary"))
        .build();
csharp
var prodStage = new Stage(app, "ProdStage", new StageProps {
    PermissionsBoundary = PermissionsBoundary.FromName("cdk-${Qualifier}-PermissionsBoundary")
});
go
prodStage := awscdk.NewStage(app, jsii.String("ProdStage"), &StageProps{
	PermissionsBoundary: awscdk.PermissionsBoundary_FromName(jsii.String("cdk-${Qualifier}-PermissionsBoundary")),
})

Any IAM Roles or Users created within this Stage will have the default permissions boundary attached.

For more details see the Permissions Boundary section in the IAM guide.

Template and Policy Validation ​

To improve iteration speed on your infrastructure and get feedback on your changes as early as possible, the CloudFormation templates produced by CDK are validated immediately after synthesis. They will be automatically validated against a comprehensive set of rules, checking for potential deployment failures and AWS best practices.

You can extend the set of validations with additional plugins if you want, like cdk-nag which is focused on standards compliance, or you can write your own organization-specific validations.

If there are any violations, the synthesis will fail and a report will be printed to the console and to a file.

CloudFormationValidatePlugin ​

By default, a default rule set is added in the form of the CloudFormationValidatePlugin, which is powered by @aws/cloudformation-validate.

This rule set checks for misconfigurations that will fail deployments (which will be reported as errors), and for violations of AWS best practices (reported as warnings). To suppress a reported warning or error, add the following to your application:

ts
const app = new App();

// You can use any scope here, closer to the violation is safer
Validations.of(app).acknowledge({
  id: 'CloudFormation-Validate::W9999',
  reason: 'This is not recommended but we have a good reason to do it like this',
});
python
app = App()

# You can use any scope here, closer to the violation is safer
Validations.of(app).acknowledge(
    id="CloudFormation-Validate::W9999",
    reason="This is not recommended but we have a good reason to do it like this"
)
java
App app = new App();

// You can use any scope here, closer to the violation is safer
Validations.of(app).acknowledge(Acknowledgment.builder()
        .id("CloudFormation-Validate::W9999")
        .reason("This is not recommended but we have a good reason to do it like this")
        .build());
csharp
var app = new App();

// You can use any scope here, closer to the violation is safer
Validations.Of(app).Acknowledge(new Acknowledgment {
    Id = "CloudFormation-Validate::W9999",
    Reason = "This is not recommended but we have a good reason to do it like this"
});
go
app := awscdk.NewApp()

// You can use any scope here, closer to the violation is safer
awscdk.Validations_Of(app).Acknowledge(&Acknowledgment{
	Id: jsii.String("CloudFormation-Validate::W9999"),
	Reason: jsii.String("This is not recommended but we have a good reason to do it like this"),
})

The plugin supports loading custom Rego or CloudFormation guard rule sets, which you can configure if you add instantiate the plugin explicitly to your app:

ts
const app = new App();

// Rules text, read from disk perhaps
declare const myRules: string;

Validations.of(app).addPlugins(new CloudFormationValidatePlugin({
  guardRules: [{
    name: 'My rules',
    content: myRules,
  }],
}));
python
from aws_cdk import ValidationRuleSource


# Rules text, read from disk perhaps
# my_rules: str
app = App()

Validations.of(app).add_plugins(CloudFormationValidatePlugin(
    guard_rules=[ValidationRuleSource(
        name="My rules",
        content=my_rules
    )]
))
java
// Rules text, read from disk perhaps
String myRules;
App app = new App();

Validations.of(app).addPlugins(CloudFormationValidatePlugin.Builder.create()
        .guardRules(List.of(ValidationRuleSource.builder()
                .name("My rules")
                .content(myRules)
                .build()))
        .build());
csharp
// Rules text, read from disk perhaps
string myRules;
var app = new App();

Validations.Of(app).AddPlugins(new CloudFormationValidatePlugin(new CloudFormationValidatePluginProps {
    GuardRules = new [] { new ValidationRuleSource {
        Name = "My rules",
        Content = myRules
    } }
}));
go
// Rules text, read from disk perhaps
var myRules string
app := awscdk.NewApp()

awscdk.Validations_Of(app).AddPlugins(awscdk.NewCloudFormationValidatePlugin(&CloudFormationValidatePluginProps{
	GuardRules: []ValidationRuleSource{
		&ValidationRuleSource{
			Name: jsii.String("My rules"),
			Content: myRules,
		},
	},
}))

In addition to the validation engine's built-in rule set, the CDK ships its own default rules that catch cross-field and cross-resource misconfigurations which pass template validation but fail (or silently misbehave) at deployment time. These run automatically on every synth. Their findings are reported as warnings unless the @aws-cdk/core:validateAgainstDefaultRules context key is set to true, in which case they become errors and fail synthesis. Suppress an individual rule by its ID using the same acknowledge mechanism shown above (for example CloudFormation-Validate::CDK-GameLift-001).

An explicitly registered CloudFormationValidatePlugin still runs the CDK default rules in addition to your custom rules; pass includeDefaultRules: false to opt out of the default rules entirely.

Additional plugins ​

You can also add custom plugins like cdk-nag and CfnGuardValidator, or author custom plugins for validation tools such as OPA.

To use one or more validation plugins in your application, use the Validations.of() API:

ts
// globally for the entire app (an app is a stage)
const app = new App();
Validations.of(app).addPlugins(new ThirdPartyPluginX());
Validations.of(app).addPlugins(new ThirdPartyPluginY());

// only apply to a particular stage
const prodStage = new Stage(app, 'ProdStage');
Validations.of(prodStage).addPlugins(new ThirdPartyPluginX());
python
# globally for the entire app (an app is a stage)
app = App()
Validations.of(app).add_plugins(ThirdPartyPluginX())
Validations.of(app).add_plugins(ThirdPartyPluginY())

# only apply to a particular stage
prod_stage = Stage(app, "ProdStage")
Validations.of(prod_stage).add_plugins(ThirdPartyPluginX())
java
// globally for the entire app (an app is a stage)
App app = new App();
Validations.of(app).addPlugins(new ThirdPartyPluginX());
Validations.of(app).addPlugins(new ThirdPartyPluginY());

// only apply to a particular stage
Stage prodStage = new Stage(app, "ProdStage");
Validations.of(prodStage).addPlugins(new ThirdPartyPluginX());
csharp
// globally for the entire app (an app is a stage)
var app = new App();
Validations.Of(app).AddPlugins(new ThirdPartyPluginX());
Validations.Of(app).AddPlugins(new ThirdPartyPluginY());

// only apply to a particular stage
var prodStage = new Stage(app, "ProdStage");
Validations.Of(prodStage).AddPlugins(new ThirdPartyPluginX());
go
// globally for the entire app (an app is a stage)
app := awscdk.NewApp()
awscdk.Validations_Of(app).AddPlugins(NewThirdPartyPluginX())
awscdk.Validations_Of(app).AddPlugins(NewThirdPartyPluginY())

// only apply to a particular stage
prodStage := awscdk.NewStage(app, jsii.String("ProdStage"))
awscdk.Validations_Of(prodStage).AddPlugins(NewThirdPartyPluginX())

Immediately after synthesis, all plugins registered this way will be invoked to validate all the templates generated in the scope you defined. In particular, if you register the templates in the App object, all templates will be subject to validation.

Warning Other than modifying the cloud assembly, plugins can do anything that your CDK application can. They can read data from the filesystem, access the network etc. It's your responsibility as the consumer of a plugin to verify that it is secure to use.

Validation Reporting ​

By default, the report is output in two ways:

  • A JSON file called policy-validation-report.json is written to the cloud assembly directory.
  • A human-readable format is printed to the standard error output.

To disable either format, explicitly set the corresponding context key to false:

ts
// Disable pretty-printed console output (JSON file still written)
const app = new App({
  context: { '@aws-cdk/core:validationReportPrettyPrint': false },
});
python
# Disable pretty-printed console output (JSON file still written)
app = App(
    context={"@aws-cdk/core:validationReportPrettyPrint": False}
)
java
// Disable pretty-printed console output (JSON file still written)
App app = App.Builder.create()
        .context(Map.of("@aws-cdk/core:validationReportPrettyPrint", false))
        .build();
csharp
// Disable pretty-printed console output (JSON file still written)
var app = new App(new AppProps {
    Context = new Dictionary<string, object> { { "@aws-cdk/core:validationReportPrettyPrint", false } }
});
go
// Disable pretty-printed console output (JSON file still written)
app := awscdk.NewApp(&AppProps{
	Context: map[string]interface{}{
		"@aws-cdk/core:validationReportPrettyPrint": jsii.Boolean(false),
	},
})

For plugin authors ​

The communication protocol between the CDK core module and your policy tool is defined by the IPolicyValidationPlugin interface. To create a new plugin you must write a class that implements this interface. There are two things you need to implement: the plugin name (by overriding the name property), and the validate() method.

The framework will call validate(), passing an IPolicyValidationContext object. The location of the templates to be validated is given by templatePaths. The plugin should return an instance of PolicyValidationPluginReport. This object represents the report that the user will receive at the end of the synthesis.

ts
class MyPlugin implements IPolicyValidationPlugin {
  public readonly name = 'MyPlugin';

  public validate(context: IPolicyValidationContext): PolicyValidationPluginReport {
    // First read the templates using context.templatePaths...

    // ...then perform the validation, and then compose and return the report.
    // Using hard-coded values here for better clarity:
    return {
      success: false,
      violations: [{
        ruleName: 'CKV_AWS_117',
        description: 'Ensure that AWS Lambda function is configured inside a VPC',
        fix: 'https://docs.bridgecrew.io/docs/ensure-that-aws-lambda-function-is-configured-inside-a-vpc-1',
        violatingResources: [{
          resourceLogicalId: 'MyFunction3BAA72D1',
          templatePath: '/home/johndoe/myapp/cdk.out/MyService.template.json',
          locations: ['Properties/VpcConfig'],
        }],
      }],
    };
  }
}
python
from aws_cdk import PolicyValidationPluginReport, PolicyViolation, PolicyViolatingResource
@jsii.implements(IPolicyValidationPlugin)
class MyPlugin:

    def validate(self, context):
        # First read the templates using context.templatePaths...

        # ...then perform the validation, and then compose and return the report.
        # Using hard-coded values here for better clarity:
        return PolicyValidationPluginReport(
            success=False,
            violations=[PolicyViolation(
                rule_name="CKV_AWS_117",
                description="Ensure that AWS Lambda function is configured inside a VPC",
                fix="https://docs.bridgecrew.io/docs/ensure-that-aws-lambda-function-is-configured-inside-a-vpc-1",
                violating_resources=[PolicyViolatingResource(
                    resource_logical_id="MyFunction3BAA72D1",
                    template_path="/home/johndoe/myapp/cdk.out/MyService.template.json",
                    locations=["Properties/VpcConfig"]
                )]
            )]
        )
java
public class MyPlugin implements IPolicyValidationPlugin {
    public final Object name;

    public PolicyValidationPluginReport validate(IPolicyValidationContext context) {
        // First read the templates using context.templatePaths...

        // ...then perform the validation, and then compose and return the report.
        // Using hard-coded values here for better clarity:
        return PolicyValidationPluginReport.builder()
                .success(false)
                .violations(List.of(PolicyViolation.builder()
                        .ruleName("CKV_AWS_117")
                        .description("Ensure that AWS Lambda function is configured inside a VPC")
                        .fix("https://docs.bridgecrew.io/docs/ensure-that-aws-lambda-function-is-configured-inside-a-vpc-1")
                        .violatingResources(List.of(PolicyViolatingResource.builder()
                                .resourceLogicalId("MyFunction3BAA72D1")
                                .templatePath("/home/johndoe/myapp/cdk.out/MyService.template.json")
                                .locations(List.of("Properties/VpcConfig"))
                                .build()))
                        .build()))
                .build();
    }
}
csharp
class MyPlugin : IPolicyValidationPlugin
{
    public readonly void Name = "MyPlugin";

    public PolicyValidationPluginReport Validate(IPolicyValidationContext context)
    {
        // First read the templates using context.templatePaths...

        // ...then perform the validation, and then compose and return the report.
        // Using hard-coded values here for better clarity:
        return new PolicyValidationPluginReport {
            Success = false,
            Violations = new [] { new PolicyViolation {
                RuleName = "CKV_AWS_117",
                Description = "Ensure that AWS Lambda function is configured inside a VPC",
                Fix = "https://docs.bridgecrew.io/docs/ensure-that-aws-lambda-function-is-configured-inside-a-vpc-1",
                ViolatingResources = new [] { new PolicyViolatingResource {
                    ResourceLogicalId = "MyFunction3BAA72D1",
                    TemplatePath = "/home/johndoe/myapp/cdk.out/MyService.template.json",
                    Locations = new [] { "Properties/VpcConfig" }
                } }
            } }
        };
    }
}
go
type myPlugin struct {
	name
}

func (this *myPlugin) validate(context IPolicyValidationContext) PolicyValidationPluginReport {
	// First read the templates using context.templatePaths...

	// ...then perform the validation, and then compose and return the report.
	// Using hard-coded values here for better clarity:
	return &PolicyValidationPluginReport{
		Success: jsii.Boolean(false),
		Violations: []PolicyViolation{
			&PolicyViolation{
				RuleName: jsii.String("CKV_AWS_117"),
				Description: jsii.String("Ensure that AWS Lambda function is configured inside a VPC"),
				Fix: jsii.String("https://docs.bridgecrew.io/docs/ensure-that-aws-lambda-function-is-configured-inside-a-vpc-1"),
				ViolatingResources: []PolicyViolatingResource{
					&PolicyViolatingResource{
						ResourceLogicalId: jsii.String("MyFunction3BAA72D1"),
						TemplatePath: jsii.String("/home/johndoe/myapp/cdk.out/MyService.template.json"),
						Locations: []*string{
							jsii.String("Properties/VpcConfig"),
						},
					},
				},
			},
		},
	}
}

In addition to the name, plugins may optionally report their version (version property) and a list of IDs of the rules they are going to evaluate (ruleIds property).

Note that plugins are not allowed to modify anything in the cloud assembly. Any attempt to do so will result in synthesis failure.

If your plugin depends on an external tool, keep in mind that some developers may not have that tool installed in their workstations yet. To minimize friction, we highly recommend that you provide some installation script along with your plugin package, to automate the whole process. Better yet, run that script as part of the installation of your package. With npm, for example, you can run add it to the postinstallscript in the package.json file.

Annotations ​

Construct authors can add annotations to constructs to report at three different levels: ERROR, WARN, INFO.

Typically warnings are added for things that are important for the user to be aware of, but will not cause deployment errors in all cases. Some common scenarios are (non-exhaustive list):

  • Warn when the user needs to take a manual action, e.g. IAM policy should be added to an referenced resource.
  • Warn if the user configuration might not follow best practices (but is still valid)
  • Warn if the user is using a deprecated API

Annotations feed into the Validations mechanism, so any construct-level *annotation you add will be reported via the validations report.

Acknowledging Warnings ​

If you would like to run with --strict mode enabled (warnings will throw errors) it is possible to acknowledge warnings to make the warning go away.

For example, if > 10 IAM managed policies are added to an IAM Group, a warning will be created:

text
IAM:Group:MaxPoliciesExceeded: You added 11 to IAM Group my-group. The maximum number of managed policies attached to an IAM group is 10.

If you have requested a quota increase you may have the ability to add > 10 managed policies which means that this warning does not apply to you. You can acknowledge this by acknowledging the warning by the id.

ts
Annotations.of(this).acknowledgeWarning('IAM:Group:MaxPoliciesExceeded', 'Account has quota increased to 20');

// Because Annotations ultimately become Validations, you can also acknowledge the Validation
Validations.of(this).acknowledge({
  id: 'Construct-Annotations::IAM:Group:MaxPoliciesExceeded',
  reason: 'Account has quota increased to 20',
});
python
Annotations.of(self).acknowledge_warning("IAM:Group:MaxPoliciesExceeded", "Account has quota increased to 20")

# Because Annotations ultimately become Validations, you can also acknowledge the Validation
Validations.of(self).acknowledge(
    id="Construct-Annotations::IAM:Group:MaxPoliciesExceeded",
    reason="Account has quota increased to 20"
)
java
Annotations.of(this).acknowledgeWarning("IAM:Group:MaxPoliciesExceeded", "Account has quota increased to 20");

// Because Annotations ultimately become Validations, you can also acknowledge the Validation
Validations.of(this).acknowledge(Acknowledgment.builder()
        .id("Construct-Annotations::IAM:Group:MaxPoliciesExceeded")
        .reason("Account has quota increased to 20")
        .build());
csharp
Annotations.Of(this).AcknowledgeWarning("IAM:Group:MaxPoliciesExceeded", "Account has quota increased to 20");

// Because Annotations ultimately become Validations, you can also acknowledge the Validation
Validations.Of(this).Acknowledge(new Acknowledgment {
    Id = "Construct-Annotations::IAM:Group:MaxPoliciesExceeded",
    Reason = "Account has quota increased to 20"
});
go
awscdk.Annotations_Of(this).AcknowledgeWarning(jsii.String("IAM:Group:MaxPoliciesExceeded"), jsii.String("Account has quota increased to 20"))

// Because Annotations ultimately become Validations, you can also acknowledge the Validation
awscdk.Validations_Of(this).Acknowledge(&Acknowledgment{
	Id: jsii.String("Construct-Annotations::IAM:Group:MaxPoliciesExceeded"),
	Reason: jsii.String("Account has quota increased to 20"),
})

Acknowledging Infos ​

Informational messages can also be emitted and acknowledged. Use addInfoV2() to add an info message that can later be suppressed with acknowledgeInfo(). Unlike warnings, info messages are not affected by the --strict mode and will never cause synthesis to fail.

ts
Annotations.of(this).addInfoV2('my-lib:Construct.someInfo', 'Some message explaining the info');
Annotations.of(this).acknowledgeInfo('my-lib:Construct.someInfo', 'This info can be ignored');

// Because Annotations ultimately become Validations, you can also acknowledge the Validation
Validations.of(this).acknowledge({
  id: 'Construct-Annotations::my-lib:Construct.someInfo',
  reason: 'Some message explaining the info',
});
python
Annotations.of(self).add_info_v2("my-lib:Construct.someInfo", "Some message explaining the info")
Annotations.of(self).acknowledge_info("my-lib:Construct.someInfo", "This info can be ignored")

# Because Annotations ultimately become Validations, you can also acknowledge the Validation
Validations.of(self).acknowledge(
    id="Construct-Annotations::my-lib:Construct.someInfo",
    reason="Some message explaining the info"
)
java
Annotations.of(this).addInfoV2("my-lib:Construct.someInfo", "Some message explaining the info");
Annotations.of(this).acknowledgeInfo("my-lib:Construct.someInfo", "This info can be ignored");

// Because Annotations ultimately become Validations, you can also acknowledge the Validation
Validations.of(this).acknowledge(Acknowledgment.builder()
        .id("Construct-Annotations::my-lib:Construct.someInfo")
        .reason("Some message explaining the info")
        .build());
csharp
Annotations.Of(this).AddInfoV2("my-lib:Construct.someInfo", "Some message explaining the info");
Annotations.Of(this).AcknowledgeInfo("my-lib:Construct.someInfo", "This info can be ignored");

// Because Annotations ultimately become Validations, you can also acknowledge the Validation
Validations.Of(this).Acknowledge(new Acknowledgment {
    Id = "Construct-Annotations::my-lib:Construct.someInfo",
    Reason = "Some message explaining the info"
});
go
awscdk.Annotations_Of(this).AddInfoV2(jsii.String("my-lib:Construct.someInfo"), jsii.String("Some message explaining the info"))
awscdk.Annotations_Of(this).AcknowledgeInfo(jsii.String("my-lib:Construct.someInfo"), jsii.String("This info can be ignored"))

// Because Annotations ultimately become Validations, you can also acknowledge the Validation
awscdk.Validations_Of(this).Acknowledge(&Acknowledgment{
	Id: jsii.String("Construct-Annotations::my-lib:Construct.someInfo"),
	Reason: jsii.String("Some message explaining the info"),
})

Mixins ​

CDK Mixins provide a new, advanced way to add functionality through composable abstractions. Unlike traditional L2 constructs that bundle all features together, Mixins allow you to pick and choose exactly the capabilities you need for constructs.

Mixins are an addition, not a replacement for construct properties. They are applied during or after construct construction using the .with() method:

ts
// Apply mixins fluently with .with()
new s3.CfnBucket(scope, "MyL1Bucket")
  .with(new BucketBlockPublicAccess())
  .with(new BucketAutoDeleteObjects());

// Apply multiple mixins to the same construct
new s3.CfnBucket(scope, "MyL1Bucket")
  .with(new BucketBlockPublicAccess(), new BucketAutoDeleteObjects());

// Mixins work with all types of constructs:
// L1, L2 and even custom constructs
new s3.Bucket(stack, 'MyL2Bucket').with(new BucketBlockPublicAccess());
new CustomBucket(stack, 'MyCustomBucket').with(new BucketBlockPublicAccess());
python
# Apply mixins fluently with .with()
s3.CfnBucket(scope, "MyL1Bucket").with(BucketBlockPublicAccess()).with(BucketAutoDeleteObjects())

# Apply multiple mixins to the same construct
s3.CfnBucket(scope, "MyL1Bucket").with(BucketBlockPublicAccess(), BucketAutoDeleteObjects())

# Mixins work with all types of constructs:
# L1, L2 and even custom constructs
s3.Bucket(stack, "MyL2Bucket").with(BucketBlockPublicAccess())
CustomBucket(stack, "MyCustomBucket").with(BucketBlockPublicAccess())
java
// Apply mixins fluently with .with()
// Apply mixins fluently with .with()
new CfnBucket(scope, "MyL1Bucket").with(new BucketBlockPublicAccess()).with(new BucketAutoDeleteObjects());

// Apply multiple mixins to the same construct
// Apply multiple mixins to the same construct
new CfnBucket(scope, "MyL1Bucket").with(new BucketBlockPublicAccess(), new BucketAutoDeleteObjects());

// Mixins work with all types of constructs:
// L1, L2 and even custom constructs
// Mixins work with all types of constructs:
// L1, L2 and even custom constructs
new Bucket(stack, "MyL2Bucket").with(new BucketBlockPublicAccess());
new CustomBucket(stack, "MyCustomBucket").with(new BucketBlockPublicAccess());
csharp
// Apply mixins fluently with .with()
// Apply mixins fluently with .with()
new CfnBucket(scope, "MyL1Bucket").With(new BucketBlockPublicAccess()).With(new BucketAutoDeleteObjects());

// Apply multiple mixins to the same construct
// Apply multiple mixins to the same construct
new CfnBucket(scope, "MyL1Bucket").With(new BucketBlockPublicAccess(), new BucketAutoDeleteObjects());

// Mixins work with all types of constructs:
// L1, L2 and even custom constructs
// Mixins work with all types of constructs:
// L1, L2 and even custom constructs
new Bucket(stack, "MyL2Bucket").With(new BucketBlockPublicAccess());
new CustomBucket(stack, "MyCustomBucket").With(new BucketBlockPublicAccess());
go
// Apply mixins fluently with .with()
// Apply mixins fluently with .with()
s3.NewCfnBucket(scope, jsii.String("MyL1Bucket")).With(awscdk.NewBucketBlockPublicAccess()).With(awscdk.NewBucketAutoDeleteObjects())

// Apply multiple mixins to the same construct
// Apply multiple mixins to the same construct
s3.NewCfnBucket(scope, jsii.String("MyL1Bucket")).With(awscdk.NewBucketBlockPublicAccess(), awscdk.NewBucketAutoDeleteObjects())

// Mixins work with all types of constructs:
// L1, L2 and even custom constructs
// Mixins work with all types of constructs:
// L1, L2 and even custom constructs
s3.NewBucket(stack, jsii.String("MyL2Bucket")).With(awscdk.NewBucketBlockPublicAccess())
NewCustomBucket(stack, jsii.String("MyCustomBucket")).With(awscdk.NewBucketBlockPublicAccess())

There is an alternative form available that allows additional, advanced configuration of Mixin application: Mixins.of().

ts
import { ConstructSelector } from "aws-cdk-lib/core";

// Basic: Apply mixins to any construct, calls can be chained
const myBucket = new s3.CfnBucket(scope, "MyBucket");
Mixins.of(myBucket)
  .apply(new BucketBlockPublicAccess())
  .apply(new BucketAutoDeleteObjects());

// Basic: Or multiple Mixins passed to apply
Mixins.of(myBucket)
  .apply(new BucketBlockPublicAccess(), new BucketAutoDeleteObjects());

// Advanced: Apply to constructs matching a selector, e.g. match by ID
Mixins.of(
  scope,
  ConstructSelector.byId("prod/**")
).apply(new CustomProdSecurityConfig());

// Advanced: Require a mixin to be applied to every node in the construct tree
Mixins.of(stack)
  .apply(new CustomProdSecurityConfig())
  .requireAll();
python
from aws_cdk import ConstructSelector


# Basic: Apply mixins to any construct, calls can be chained
my_bucket = s3.CfnBucket(scope, "MyBucket")
Mixins.of(my_bucket).apply(BucketBlockPublicAccess()).apply(BucketAutoDeleteObjects())

# Basic: Or multiple Mixins passed to apply
Mixins.of(my_bucket).apply(BucketBlockPublicAccess(), BucketAutoDeleteObjects())

# Advanced: Apply to constructs matching a selector, e.g. match by ID
Mixins.of(scope,
    ConstructSelector.by_id("prod/**")).apply(CustomProdSecurityConfig())

# Advanced: Require a mixin to be applied to every node in the construct tree
Mixins.of(stack).apply(CustomProdSecurityConfig()).require_all()
java
import software.amazon.awscdk.ConstructSelector;


// Basic: Apply mixins to any construct, calls can be chained
CfnBucket myBucket = new CfnBucket(scope, "MyBucket");
Mixins.of(myBucket).apply(new BucketBlockPublicAccess()).apply(new BucketAutoDeleteObjects());

// Basic: Or multiple Mixins passed to apply
Mixins.of(myBucket).apply(new BucketBlockPublicAccess(), new BucketAutoDeleteObjects());

// Advanced: Apply to constructs matching a selector, e.g. match by ID
Mixins.of(scope, ConstructSelector.byId("prod/**")).apply(new CustomProdSecurityConfig());

// Advanced: Require a mixin to be applied to every node in the construct tree
Mixins.of(stack).apply(new CustomProdSecurityConfig()).requireAll();
csharp
using Amazon.CDK;


// Basic: Apply mixins to any construct, calls can be chained
var myBucket = new CfnBucket(scope, "MyBucket");
Mixins.Of(myBucket).Apply(new BucketBlockPublicAccess()).Apply(new BucketAutoDeleteObjects());

// Basic: Or multiple Mixins passed to apply
Mixins.Of(myBucket).Apply(new BucketBlockPublicAccess(), new BucketAutoDeleteObjects());

// Advanced: Apply to constructs matching a selector, e.g. match by ID
Mixins.Of(scope, ConstructSelector.ById("prod/**")).Apply(new CustomProdSecurityConfig());

// Advanced: Require a mixin to be applied to every node in the construct tree
Mixins.Of(stack).Apply(new CustomProdSecurityConfig()).RequireAll();
go
import "github.com/aws/aws-cdk-go/awscdk"


// Basic: Apply mixins to any construct, calls can be chained
myBucket := s3.NewCfnBucket(scope, jsii.String("MyBucket"))
awscdk.Mixins_Of(myBucket).Apply(awscdk.NewBucketBlockPublicAccess()).Apply(awscdk.NewBucketAutoDeleteObjects())

// Basic: Or multiple Mixins passed to apply
awscdk.Mixins_Of(myBucket).Apply(awscdk.NewBucketBlockPublicAccess(), awscdk.NewBucketAutoDeleteObjects())

// Advanced: Apply to constructs matching a selector, e.g. match by ID
awscdk.Mixins_Of(scope, awscdk.ConstructSelector_ById(jsii.String("prod/**"))).Apply(NewCustomProdSecurityConfig())

// Advanced: Require a mixin to be applied to every node in the construct tree
awscdk.Mixins_Of(stack).Apply(NewCustomProdSecurityConfig()).RequireAll()

How Mixins are applied ​

Each construct has a with() method and Mixins will be applied to all nodes of the construct. Sometimes more control is needed. Especially when authoring construct libraries, it may be desirable to have full control over the Mixin application process. Think of the L3 pattern again: How can you encode the rules to which Mixins may or may not be applied in your L3? This is where Mixins.of() and the MixinApplicator class come in. They provide more complex ways to select targets, apply Mixins and set expectations.

Mixin application on construct trees ​

When working with construct trees like Stacks (as opposed to single resources), Mixins.of() offers a more comprehensive API to configure how Mixins are applied. By default, Mixins are applied to all supported constructs in the tree:

ts
// Apply to all constructs in a scope
Mixins.of(scope).apply(new BucketBlockPublicAccess());
python
# Apply to all constructs in a scope
Mixins.of(scope).apply(BucketBlockPublicAccess())
java
// Apply to all constructs in a scope
Mixins.of(scope).apply(new BucketBlockPublicAccess());
csharp
// Apply to all constructs in a scope
Mixins.Of(scope).Apply(new BucketBlockPublicAccess());
go
// Apply to all constructs in a scope
awscdk.Mixins_Of(scope).Apply(awscdk.NewBucketBlockPublicAccess())

Optionally, you may select specific constructs:

ts
import { ConstructSelector } from "aws-cdk-lib/core";

// Apply to a given L1 resource or L2 resource construct
Mixins.of(
  bucket,
  ConstructSelector.cfnResource() // provided CfnResource or a CfnResource default child
).apply(new BucketBlockPublicAccess());

// Apply to all resources of a specific type
Mixins.of(
  scope,
  ConstructSelector.resourcesOfType(s3.CfnBucket.CFN_RESOURCE_TYPE_NAME)
).apply(new BucketBlockPublicAccess());

// Alternative: select by CloudFormation resource type name
Mixins.of(
  scope,
  ConstructSelector.resourcesOfType("AWS::S3::Bucket")
).apply(new BucketBlockPublicAccess());

// Apply to constructs matching a pattern
Mixins.of(
  scope,
  ConstructSelector.byId("prod/**")
).apply(new CustomProdSecurityConfig());

// The default is to apply to all constructs in the scope
Mixins.of(
  scope,
  ConstructSelector.all() // pass through to IConstruct.findAll()
).apply(new CustomProdSecurityConfig());
python
from aws_cdk import ConstructSelector


# Apply to a given L1 resource or L2 resource construct
Mixins.of(bucket,
    ConstructSelector.cfn_resource()).apply(BucketBlockPublicAccess())

# Apply to all resources of a specific type
Mixins.of(scope,
    ConstructSelector.resources_of_type(s3.CfnBucket.CFN_RESOURCE_TYPE_NAME)).apply(BucketBlockPublicAccess())

# Alternative: select by CloudFormation resource type name
Mixins.of(scope,
    ConstructSelector.resources_of_type("AWS::S3::Bucket")).apply(BucketBlockPublicAccess())

# Apply to constructs matching a pattern
Mixins.of(scope,
    ConstructSelector.by_id("prod/**")).apply(CustomProdSecurityConfig())

# The default is to apply to all constructs in the scope
Mixins.of(scope,
    ConstructSelector.all()).apply(CustomProdSecurityConfig())
java
import software.amazon.awscdk.ConstructSelector;


// Apply to a given L1 resource or L2 resource construct
Mixins.of(bucket, ConstructSelector.cfnResource()).apply(new BucketBlockPublicAccess());

// Apply to all resources of a specific type
Mixins.of(scope, ConstructSelector.resourcesOfType(CfnBucket.CFN_RESOURCE_TYPE_NAME)).apply(new BucketBlockPublicAccess());

// Alternative: select by CloudFormation resource type name
Mixins.of(scope, ConstructSelector.resourcesOfType("AWS::S3::Bucket")).apply(new BucketBlockPublicAccess());

// Apply to constructs matching a pattern
Mixins.of(scope, ConstructSelector.byId("prod/**")).apply(new CustomProdSecurityConfig());

// The default is to apply to all constructs in the scope
Mixins.of(scope, ConstructSelector.all()).apply(new CustomProdSecurityConfig());
csharp
using Amazon.CDK;


// Apply to a given L1 resource or L2 resource construct
Mixins.Of(bucket, ConstructSelector.CfnResource()).Apply(new BucketBlockPublicAccess());

// Apply to all resources of a specific type
Mixins.Of(scope, ConstructSelector.ResourcesOfType(CfnBucket.CFN_RESOURCE_TYPE_NAME)).Apply(new BucketBlockPublicAccess());

// Alternative: select by CloudFormation resource type name
Mixins.Of(scope, ConstructSelector.ResourcesOfType("AWS::S3::Bucket")).Apply(new BucketBlockPublicAccess());

// Apply to constructs matching a pattern
Mixins.Of(scope, ConstructSelector.ById("prod/**")).Apply(new CustomProdSecurityConfig());

// The default is to apply to all constructs in the scope
Mixins.Of(scope, ConstructSelector.All()).Apply(new CustomProdSecurityConfig());
go
import "github.com/aws/aws-cdk-go/awscdk"


// Apply to a given L1 resource or L2 resource construct
awscdk.Mixins_Of(bucket, awscdk.ConstructSelector_CfnResource()).Apply(awscdk.NewBucketBlockPublicAccess())

// Apply to all resources of a specific type
awscdk.Mixins_Of(scope, awscdk.ConstructSelector_ResourcesOfType(s3.CfnBucket_CFN_RESOURCE_TYPE_NAME())).Apply(awscdk.NewBucketBlockPublicAccess())

// Alternative: select by CloudFormation resource type name
awscdk.Mixins_Of(scope, awscdk.ConstructSelector_ResourcesOfType(jsii.String("AWS::S3::Bucket"))).Apply(awscdk.NewBucketBlockPublicAccess())

// Apply to constructs matching a pattern
awscdk.Mixins_Of(scope, awscdk.ConstructSelector_ById(jsii.String("prod/**"))).Apply(NewCustomProdSecurityConfig())

// The default is to apply to all constructs in the scope
awscdk.Mixins_Of(scope, awscdk.ConstructSelector_All()).Apply(NewCustomProdSecurityConfig())

Mixins that must be used ​

Sometimes you need assertions that a Mixin has been applied to certain set of constructs. Mixins.of(...) keeps track of Mixin applications and this report can be used to create assertions.

It comes with two convenience helpers: Use requireAll() to assert the Mixin will be applied to all selected constructs. If a construct is in the selection that is not supported by the Mixin, this will throw an error. The requireAny() helper will assert the Mixin was applied to at least one construct from the selection. If the Mixin wasn't applied to any construct at all, this will throw an error.

Both helpers will only check future calls of apply(). Set them before calling apply() to take effect.

ts
Mixins.of(scope, selector)
  // Assert Mixin was applied to all constructs in the selection
  .requireAll()
  // Or assert Mixin was applied to at least one construct in the selection
  // .requireAny()
  .apply(new BucketBlockPublicAccess());

// Get an application report for manual assertions
const report = Mixins.of(scope).apply(new BucketBlockPublicAccess()).report;
python
Mixins.of(scope, selector).require_all().apply(BucketBlockPublicAccess())

# Get an application report for manual assertions
report = Mixins.of(scope).apply(BucketBlockPublicAccess()).report
java
Mixins.of(scope, selector).requireAll().apply(new BucketBlockPublicAccess());

// Get an application report for manual assertions
MixinApplication[] report = Mixins.of(scope).apply(new BucketBlockPublicAccess()).getReport();
csharp
Mixins.Of(scope, selector).RequireAll().Apply(new BucketBlockPublicAccess());

// Get an application report for manual assertions
var report = Mixins.Of(scope).Apply(new BucketBlockPublicAccess()).Report;
go
awscdk.Mixins_Of(scope, selector).RequireAll().Apply(awscdk.NewBucketBlockPublicAccess())

// Get an application report for manual assertions
report := awscdk.Mixins_Of(scope).Apply(awscdk.NewBucketBlockPublicAccess()).report

Creating Custom Mixins ​

Mixins are simple classes that implement the IMixin interface (usually by extending the abstract Mixin class):

ts
class EnableVersioning extends Mixin implements IMixin {
  supports(construct: any): construct is s3.CfnBucket {
    return s3.CfnBucket.isCfnBucket(construct);
  }

  applyTo(bucket: IConstruct): void {
    (bucket as s3.CfnBucket).versioningConfiguration = {
      status: "Enabled"
    };
  }
}

// Usage
new s3.CfnBucket(scope, "MyBucket")
  .with(new EnableVersioning());
python
@jsii.implements(IMixin)
class EnableVersioning(Mixin):
    def supports(self, construct):
        return s3.CfnBucket.is_cfn_bucket(construct)

    def apply_to(self, bucket):
        (bucket).versioning_configuration = s3.CfnBucket.VersioningConfigurationProperty(
            status="Enabled"
        )

# Usage
s3.CfnBucket(scope, "MyBucket").with(EnableVersioning())
java
public class EnableVersioning extends Mixin implements IMixin {
    public boolean supports(Object construct) {
        return CfnBucket.isCfnBucket(construct);
    }

    public void applyTo(IConstruct bucket) {
        ((CfnBucket)bucket).getVersioningConfiguration() = VersioningConfigurationProperty.builder()
                .status("Enabled")
                .build();
    }
}

// Usage
// Usage
new CfnBucket(scope, "MyBucket").with(new EnableVersioning());
csharp
class EnableVersioning : Mixin, IMixin
{
    public boolean Supports(object construct)
    {
        return CfnBucket.IsCfnBucket(construct);
    }

    public void ApplyTo(IConstruct bucket)
    {
        ((CfnBucket)bucket).VersioningConfiguration = new VersioningConfigurationProperty {
            Status = "Enabled"
        };
    }
}

// Usage
// Usage
new CfnBucket(scope, "MyBucket").With(new EnableVersioning());
go
type enableVersioning struct {
	Mixin
}

func (this *enableVersioning) supports(construct interface{}) *bool {
	return s3.CfnBucket_IsCfnBucket(*construct)
}

func (this *enableVersioning) applyTo(bucket IConstruct) {
	(*bucket.(CfnBucket)).versioningConfiguration = &VersioningConfigurationProperty{
		Status: jsii.String("Enabled"),
	}
}

// Usage
// Usage
s3.NewCfnBucket(scope, jsii.String("MyBucket")).With(NewEnableVersioning())

We recommend to implement Mixins at the L1 level and to have them target a specific resource construct. This way, the same Mixin can be applied to constructs from all levels.

When applied, the .supports() method is used to decided if a Mixin can be applied to a given construct. Depending on the application method (see below), the Mixin is then applied, skipped or an error is thrown.

ts
bucketAccessLogsMixin.supports(bucket); // returns `true`
bucketAccessLogsMixin.supports(queue); // returns `false`
python
bucket_access_logs_mixin.supports(bucket) # returns `true`
bucket_access_logs_mixin.supports(queue)
java
bucketAccessLogsMixin.supports(bucket); // returns `true`
bucketAccessLogsMixin.supports(queue);
csharp
bucketAccessLogsMixin.Supports(bucket); // returns `true`
bucketAccessLogsMixin.Supports(queue);
go
bucketAccessLogsMixin.Supports(bucket) // returns `true`
bucketAccessLogsMixin.Supports(queue)

Validation with Mixins ​

Mixins have two distinct phases: Initialization and application. During initialization only the Mixin's input properties are available, but during application we also have access the target construct.

Mixins should validate their properties and targets as early as possible. During initialization validate all input properties. Then during application validate any target dependent pre-conditions or interactions with Mixin properties.

Like with constructs, Mixins should throw an error in case of unrecoverable failures and use annotations for recoverable ones. It is best practices to collect errors and throw as a group whenever possible. Mixins can attach lazy validators to the target construct. Use this to ensure a certain property is met at end of an app's execution.

ts
class MyEncryptionAtRest extends Mixin {
  constructor(props: MyEncryptionAtRestProps = {}) {
    super();
    // Validate Mixin props at construction time
    if (props.bucketKey && props.algorithm === 'aws:kms:dsse') {
      throw new Error("Cannot use S3 Bucket Key and DSSE together");
    }
  }

  supports(construct: any): construct is s3.CfnBucket {
    return s3.CfnBucket.isCfnBucket(construct);
  }

  applyTo(target: s3.CfnBucket): s3.CfnBucket {
    // Validate pre-conditions on the target, throw if error is unrecoverable
    if (!target.bucketEncryption) {
      throw new Error("Bucket encryption not configured");
    }

    // Validate properties are met after app execution
    target.node.addValidation({
      validate: () => isKmsEncrypted(target)
        ? ['This bucket must use aws:kms encryption.']
        : []
    });

    target.bucketEncryption = {
      serverSideEncryptionConfiguration: [{
        bucketKeyEnabled: true,
        serverSideEncryptionByDefault: {
          sseAlgorithm: "aws:kms"
        }
      }]
    };
    return target;
  }
}
python
class MyEncryptionAtRest(Mixin):
    def __init__(self, *, bucketKey=None, algorithm=None):
        super().__init__()
        # Validate Mixin props at construction time
        if bucket_key && algorithm == "aws:kms:dsse": throw new Error("Cannot use S3 Bucket Key and DSSE together");

    def supports(self, construct):
        return s3.CfnBucket.is_cfn_bucket(construct)

    def apply_to(self, target):
        # Validate pre-conditions on the target, throw if error is unrecoverable
        if not target.bucket_encryption: throw new Error("Bucket encryption not configured");

        # Validate properties are met after app execution
        target.node.add_validation({
            "validate": () => isKmsEncrypted(target)
                    ? ['This bucket must use aws:kms encryption.']
                    : []
        })

        target.bucket_encryption = s3.CfnBucket.BucketEncryptionProperty(
            server_side_encryption_configuration=[s3.CfnBucket.ServerSideEncryptionRuleProperty(
                bucket_key_enabled=True,
                server_side_encryption_by_default=s3.CfnBucket.ServerSideEncryptionByDefaultProperty(
                    sse_algorithm="aws:kms"
                )
            )]
        )
        return target
java
public class MyEncryptionAtRest extends Mixin {
    public MyEncryptionAtRest() {
        this(new MyEncryptionAtRestProps());
    }

    public MyEncryptionAtRest(MyEncryptionAtRestProps props) {
        super();
        // Validate Mixin props at construction time
        if (props.getBucketKey() && props.getAlgorithm() == "aws:kms:dsse") {throw new Error("Cannot use S3 Bucket Key and DSSE together");
        }
    }

    public boolean supports(Object construct) {
        return CfnBucket.isCfnBucket(construct);
    }

    public CfnBucket applyTo(CfnBucket target) {
        // Validate pre-conditions on the target, throw if error is unrecoverable
        if (!target.getBucketEncryption()) {throw new Error("Bucket encryption not configured");
        }

        // Validate properties are met after app execution
        target.node.addValidation(Map.of(
                "validate", () => isKmsEncrypted(target)
                        ? ['This bucket must use aws:kms encryption.']
                        : []));

        target.getBucketEncryption() = BucketEncryptionProperty.builder()
                .serverSideEncryptionConfiguration(List.of(ServerSideEncryptionRuleProperty.builder()
                        .bucketKeyEnabled(true)
                        .serverSideEncryptionByDefault(ServerSideEncryptionByDefaultProperty.builder()
                                .sseAlgorithm("aws:kms")
                                .build())
                        .build()))
                .build();
        return target;
    }
}
csharp
class MyEncryptionAtRest : Mixin
{
    public MyEncryptionAtRest(MyEncryptionAtRestProps props=new MyEncryptionAtRestProps { }) : base()
    {
        // Validate Mixin props at construction time
        if (props.BucketKey && props.Algorithm == "aws:kms:dsse")
        {throw new Error("Cannot use S3 Bucket Key and DSSE together");
        }
    }

    public boolean Supports(object construct)
    {
        return CfnBucket.IsCfnBucket(construct);
    }

    public CfnBucket ApplyTo(CfnBucket target)
    {
        // Validate pre-conditions on the target, throw if error is unrecoverable
        if (!target.BucketEncryption)
        {throw new Error("Bucket encryption not configured");
        }

        // Validate properties are met after app execution
        target.Node.AddValidation(new Dictionary<string, validate> {
            { "validate", () => isKmsEncrypted(target)
                    ? ['This bucket must use aws:kms encryption.']
                    : [] }
        });

        target.BucketEncryption = new BucketEncryptionProperty {
            ServerSideEncryptionConfiguration = new [] { new ServerSideEncryptionRuleProperty {
                BucketKeyEnabled = true,
                ServerSideEncryptionByDefault = new ServerSideEncryptionByDefaultProperty {
                    SseAlgorithm = "aws:kms"
                }
            } }
        };
        return target;
    }
}
go
type myEncryptionAtRest struct {
	Mixin
}

func newMyEncryptionAtRest(props myEncryptionAtRestProps) *myEncryptionAtRest {
	if props == nil {
		props = &myEncryptionAtRestProps{
		}
	}
	this := &myEncryptionAtRest{}
	newMixin_Override(this, )
	// Validate Mixin props at construction time
	if *props.bucketKey && *props.algorithm == "aws:kms:dsse" {throw new Error("Cannot use S3 Bucket Key and DSSE together");
	}
	return this
}

func (this *myEncryptionAtRest) supports(construct interface{}) *bool {
	return s3.CfnBucket_IsCfnBucket(*construct)
}

func (this *myEncryptionAtRest) applyTo(target CfnBucket) CfnBucket {
	// Validate pre-conditions on the target, throw if error is unrecoverable
	if !*target.bucketEncryption {throw new Error("Bucket encryption not configured");
	}

	// Validate properties are met after app execution
	*target.Node.AddValidation(map[string]validate{
		"validate": () => isKmsEncrypted(target)
		        ? ['This bucket must use aws:kms encryption.']
		        : [],
	})

	*target.bucketEncryption = &BucketEncryptionProperty{
		ServerSideEncryptionConfiguration: []interface{}{
			&ServerSideEncryptionRuleProperty{
				BucketKeyEnabled: jsii.Boolean(true),
				ServerSideEncryptionByDefault: &ServerSideEncryptionByDefaultProperty{
					SseAlgorithm: jsii.String("aws:kms"),
				},
			},
		},
	}
	return *target
}

Mixins and Aspects ​

Mixins and Aspects are similar concepts and both are implementations of the visitor pattern. They crucially differ in their time of application:

  • Mixins are always applied immediately, they are a tool of imperative programming.
  • Aspects are applied after all other code during the synthesis phase, this makes them declarative.

Both Mixins and Aspects have valid use cases and complement each other. We recommend to use Mixins to make changes, and to use Aspects to validate behaviors. Aspects may also be used when changes need to apply to future additions, for examples in custom libraries.

Aspects ​

Aspects is a feature in CDK that allows you to apply operations or transformations across all constructs in a construct tree. Common use cases include tagging resources, enforcing encryption on S3 Buckets, or applying specific security or compliance rules to all resources in a stack.

Conceptually, there are two types of Aspects:

  • Read-only aspects scan the construct tree but do not make changes to the tree. Common use cases of read-only aspects include performing validations (for example, enforcing that all S3 Buckets have versioning enabled) and logging (for example, collecting information about all deployed resources for audits or compliance).
  • Mutating aspects either (1.) add new nodes or (2.) mutate existing nodes of the tree in-place. One commonly used mutating Aspect is adding Tags to resources. An example of an Aspect that adds a node is one that automatically adds a security group to every EC2 instance in the construct tree if no default is specified.

Here is a simple example of creating and applying an Aspect on a Stack to enable versioning on all S3 Buckets:

ts
class EnableBucketVersioning implements IAspect {
  visit(node: IConstruct) {
    if (node instanceof s3.CfnBucket) {
      node.versioningConfiguration = {
        status: 'Enabled'
      };
    }
  }
}

const app = new App();
const stack = new MyStack(app, 'MyStack');

// Apply the aspect to enable versioning on all S3 Buckets
Aspects.of(stack).add(new EnableBucketVersioning());
python
@jsii.implements(IAspect)
class EnableBucketVersioning:
    def visit(self, node):
        if node instanceof s3.CfnBucket:
            node.versioning_configuration = s3.CfnBucket.VersioningConfigurationProperty(
                status="Enabled"
            )

app = App()
stack = MyStack(app, "MyStack")

# Apply the aspect to enable versioning on all S3 Buckets
Aspects.of(stack).add(EnableBucketVersioning())
java
public class EnableBucketVersioning implements IAspect {
    public void visit(IConstruct node) {
        if (node instanceof CfnBucket) {
            node.getVersioningConfiguration() = VersioningConfigurationProperty.builder()
                    .status("Enabled")
                    .build();
        }
    }
}

App app = new App();
MyStack stack = new MyStack(app, "MyStack");

// Apply the aspect to enable versioning on all S3 Buckets
Aspects.of(stack).add(new EnableBucketVersioning());
csharp
class EnableBucketVersioning : IAspect
{
    public void Visit(IConstruct node)
    {
        if (node instanceof CfnBucket)
        {
            node.VersioningConfiguration = new VersioningConfigurationProperty {
                Status = "Enabled"
            };
        }
    }
}

var app = new App();
var stack = new MyStack(app, "MyStack");

// Apply the aspect to enable versioning on all S3 Buckets
Aspects.Of(stack).Add(new EnableBucketVersioning());
go
type enableBucketVersioning struct {
}

func (this *enableBucketVersioning) visit(node IConstruct) {
	if *node instanceof s3.CfnBucket {
		*node.versioningConfiguration = &VersioningConfigurationProperty{
			Status: jsii.String("Enabled"),
		}
	}
}

app := awscdk.NewApp()
stack := NewMyStack(app, jsii.String("MyStack"))

// Apply the aspect to enable versioning on all S3 Buckets
awscdk.Aspects_Of(stack).Add(NewEnableBucketVersioning())

Aspect Stabilization ​

The modern behavior is that Aspects automatically run on newly added nodes to the construct tree. This is controlled by the flag @aws-cdk/core:aspectStabilization, which is default for new projects (since version 2.172.0).

The old behavior of Aspects (without stabilization) was that Aspect invocation runs once on the entire construct tree. This meant that nested Aspects (Aspects that create new Aspects) are not invoked and nodes created by Aspects at a higher level of the construct tree are not visited.

To enable the stabilization behavior for older versions, use this feature by putting the following into your cdk.context.json:

json
{
  "@aws-cdk/core:aspectStabilization": true
}

Aspect Priorities ​

Users can specify the order in which Aspects are applied on a construct by using the optional priority parameter when applying an Aspect. Priority values must be non-negative integers, where a higher number means the Aspect will be applied later, and a lower number means it will be applied sooner.

By default, newly created nodes always inherit aspects. Priorities are mainly for ordering between mutating aspects on the construct tree.

CDK provides standard priority values for mutating and readonly aspects to help ensure consistency across different construct libraries. Note that Aspects that have same priority value are not guaranteed to be executed in a consistent order.

ts
/**
 * Default Priority values for Aspects.
 */
class AspectPriority {
  /**
   * Suggested priority for Aspects that mutate the construct tree.
   */
  static readonly MUTATING: number = 200;

  /**
   * Suggested priority for Aspects that only read the construct tree.
   */
  static readonly READONLY: number = 1000;

  /**
   * Default priority for Aspects that are applied without a priority.
   */
  static readonly DEFAULT: number = 500;
}
python
#
# Default Priority values for Aspects.
#
class AspectPriority:
java
/**
 * Default Priority values for Aspects.
 */
public class AspectPriority {
    /**
       * Suggested priority for Aspects that mutate the construct tree.
       */
    public final Number MUTATING;

    /**
       * Suggested priority for Aspects that only read the construct tree.
       */
    public final Number READONLY;

    /**
       * Default priority for Aspects that are applied without a priority.
       */
    public final Number DEFAULT;
}
csharp
/**
 * Default Priority values for Aspects.
 */
class AspectPriority
{
    /**
       * Suggested priority for Aspects that mutate the construct tree.
       */
    public readonly int MUTATING = 200;

    /**
       * Suggested priority for Aspects that only read the construct tree.
       */
    public readonly int READONLY = 1000;

    /**
       * Default priority for Aspects that are applied without a priority.
       */
    public readonly int DEFAULT = 500;
}
go
/**
 * Default Priority values for Aspects.
 */
type aspectPriority struct {
	/**
	   * Suggested priority for Aspects that mutate the construct tree.
	   */
	MUTATING *f64

	/**
	   * Suggested priority for Aspects that only read the construct tree.
	   */
	READONLY *f64

	/**
	   * Default priority for Aspects that are applied without a priority.
	   */
	DEFAULT *f64
}

If no priority is provided, the default value will be 500. This ensures that aspects without a specified priority run after mutating aspects but before any readonly aspects.

Correctly applying Aspects with priority values ensures that mutating aspects (such as adding tags or resources) run before validation aspects. This allows users to avoid misconfigurations and ensure that the final construct tree is fully validated before being synthesized.

Applying Aspects with Priority ​

ts
class MutatingAspect implements IAspect {
  visit(node: IConstruct) {
    // Modifies a resource in some way
  }
}

class ValidationAspect implements IAspect {
  visit(node: IConstruct) {
    // Perform some readonly validation on the cosntruct tree
  }
}

const stack = new Stack();

Aspects.of(stack).add(new MutatingAspect(), { priority: AspectPriority.MUTATING } );  // Run first (mutating aspects)
Aspects.of(stack).add(new ValidationAspect(), { priority: AspectPriority.READONLY } );  // Run later (readonly aspects)
python
@jsii.implements(IAspect)
class MutatingAspect:
    def visit(self, node):
        pass

@jsii.implements(IAspect)
class ValidationAspect:
    def visit(self, node):
        pass

stack = Stack()

Aspects.of(stack).add(MutatingAspect(), priority=AspectPriority.MUTATING) # Run first (mutating aspects)
Aspects.of(stack).add(ValidationAspect(), priority=AspectPriority.READONLY)
java
public class MutatingAspect implements IAspect {
    public void visit(IConstruct node) {
    }
}

public class ValidationAspect implements IAspect {
    public void visit(IConstruct node) {
    }
}

Stack stack = new Stack();

Aspects.of(stack).add(new MutatingAspect(), AspectOptions.builder().priority(AspectPriority.MUTATING).build()); // Run first (mutating aspects)
Aspects.of(stack).add(new ValidationAspect(), AspectOptions.builder().priority(AspectPriority.READONLY).build());
csharp
class MutatingAspect : IAspect
{
    public void Visit(IConstruct node)
    {
    }
}

class ValidationAspect : IAspect
{
    public void Visit(IConstruct node)
    {
    }
}

var stack = new Stack();

Aspects.Of(stack).Add(new MutatingAspect(), new AspectOptions { Priority = AspectPriority.MUTATING }); // Run first (mutating aspects)
Aspects.Of(stack).Add(new ValidationAspect(), new AspectOptions { Priority = AspectPriority.READONLY });
go
type mutatingAspect struct {
}

func (this *mutatingAspect) visit(node IConstruct) {}

type validationAspect struct {
}

func (this *validationAspect) visit(node IConstruct) {}

stack := awscdk.Newstack()

awscdk.Aspects_Of(stack).Add(NewMutatingAspect(), &AspectOptions{
	Priority: awscdk.AspectPriority_MUTATING(),
}) // Run first (mutating aspects)
awscdk.Aspects_Of(stack).Add(NewValidationAspect(), &AspectOptions{
	Priority: awscdk.AspectPriority_READONLY(),
})

Inspecting applied aspects and changing priorities ​

We also give customers the ability to view all of their applied aspects and override the priority on these aspects. The AspectApplication class represents an Aspect that is applied to a node of the construct tree with a priority.

Users can access AspectApplications on a node by calling applied from the Aspects class as follows:

ts
declare const root: Construct;
const app = new App();
const stack = new MyStack(app, 'MyStack');

Aspects.of(stack).add(new MyAspect());

let aspectApplications: AspectApplication[] = Aspects.of(root).applied;

for (const aspectApplication of aspectApplications) {
  // The aspect we are applying
  console.log(aspectApplication.aspect);
  // The construct we are applying the aspect to
  console.log(aspectApplication.construct);
  // The priority it was applied with
  console.log(aspectApplication.priority);

  // Change the priority
  aspectApplication.priority = 700;
}
python
# root: Construct

app = App()
stack = MyStack(app, "MyStack")

Aspects.of(stack).add(MyAspect())

aspect_applications = Aspects.of(root).applied

for aspect_application in aspect_applications:
    # The aspect we are applying
    print(aspect_application.aspect)
    # The construct we are applying the aspect to
    print(aspect_application.construct)
    # The priority it was applied with
    print(aspect_application.priority)

    # Change the priority
    aspect_application.priority = 700
java
Construct root;

App app = new App();
MyStack stack = new MyStack(app, "MyStack");

Aspects.of(stack).add(new MyAspect());

AspectApplication[] aspectApplications = Aspects.of(root).getApplied();

for (Object aspectApplication : aspectApplications) {
    // The aspect we are applying
    System.out.println(aspectApplication.getAspect());
    // The construct we are applying the aspect to
    System.out.println(aspectApplication.getConstruct());
    // The priority it was applied with
    System.out.println(aspectApplication.getPriority());

    // Change the priority
    aspectApplication.getPriority() = 700;
}
csharp
Construct root;

var app = new App();
var stack = new MyStack(app, "MyStack");

Aspects.Of(stack).Add(new MyAspect());

var aspectApplications = Aspects.Of(root).Applied;

for (var aspectApplication in aspectApplications)
{
    // The aspect we are applying
    Console.WriteLine(aspectApplication.Aspect);
    // The construct we are applying the aspect to
    Console.WriteLine(aspectApplication.Construct);
    // The priority it was applied with
    Console.WriteLine(aspectApplication.Priority);

    // Change the priority
    aspectApplication.Priority = 700;
}
go
var root Construct

app := awscdk.NewApp()
stack := NewMyStack(app, jsii.String("MyStack"))

awscdk.Aspects_Of(stack).Add(NewMyAspect())

aspectApplications := awscdk.Aspects_Of(root).applied

for _, aspectApplication := range aspectApplications {
	// The aspect we are applying
	fmt.Println(aspectApplication.Aspect)
	// The construct we are applying the aspect to
	fmt.Println(aspectApplication.Construct)
	// The priority it was applied with
	fmt.Println(aspectApplication.priority)

	// Change the priority
	aspectApplication.priority = 700
}

Converting between Aspects and Mixins ​

Since Mixins and Aspects are both implementations of the visitor pattern, they can be converted from each other using the Shims class:

ts
// Applies an Aspect immediately as a Mixin
const versioningMixin = Shims.asMixin(new EnableBucketVersioning());
Mixins.of(scope).apply(versioningMixin);

// Delays application of a Mixin to the synthesis phase
const publicAccessAspect = Shims.asAspect(new BucketBlockPublicAccess());
Aspects.of(scope).add(publicAccessAspect);
python
# Applies an Aspect immediately as a Mixin
versioning_mixin = Shims.as_mixin(EnableBucketVersioning())
Mixins.of(scope).apply(versioning_mixin)

# Delays application of a Mixin to the synthesis phase
public_access_aspect = Shims.as_aspect(BucketBlockPublicAccess())
Aspects.of(scope).add(public_access_aspect)
java
// Applies an Aspect immediately as a Mixin
IMixin versioningMixin = Shims.asMixin(new EnableBucketVersioning());
Mixins.of(scope).apply(versioningMixin);

// Delays application of a Mixin to the synthesis phase
IAspect publicAccessAspect = Shims.asAspect(new BucketBlockPublicAccess());
Aspects.of(scope).add(publicAccessAspect);
csharp
// Applies an Aspect immediately as a Mixin
var versioningMixin = Shims.AsMixin(new EnableBucketVersioning());
Mixins.Of(scope).Apply(versioningMixin);

// Delays application of a Mixin to the synthesis phase
var publicAccessAspect = Shims.AsAspect(new BucketBlockPublicAccess());
Aspects.Of(scope).Add(publicAccessAspect);
go
// Applies an Aspect immediately as a Mixin
versioningMixin := awscdk.Shims_AsMixin(NewEnableBucketVersioning())
awscdk.Mixins_Of(scope).Apply(versioningMixin)

// Delays application of a Mixin to the synthesis phase
publicAccessAspect := awscdk.Shims_AsAspect(awscdk.NewBucketBlockPublicAccess())
awscdk.Aspects_Of(scope).Add(publicAccessAspect)

When shimming a Mixin to an Aspect, the Mixin will automatically only be applied to supported constructs (via supports()). Going from an Aspect to a Mixin, the Aspect will be applied to every node.

Blueprint Property Injection ​

The goal of Blueprint Property Injection is to provide builders an automatic way to set default property values.

Construct authors can declare that a Construct can have it properties injected by adding @propertyInjectable class decorator and specifying PROPERTY_INJECTION_ID readonly property. All L2 Constructs will support Property Injection so organizations can write injectors to set their Construct Props.

Organizations can set default property values to a Construct by writing Injectors for builders to consume.

Here is a simple example of an Injector for APiKey that sets enabled to false.

ts
class ApiKeyPropsInjector implements IPropertyInjector {
  readonly constructUniqueId: string;

  constructor() {
    this.constructUniqueId = api.ApiKey.PROPERTY_INJECTION_ID;
  }

  inject(originalProps: api.ApiKeyProps, context: InjectionContext): api.ApiKeyProps {
    return {
      enabled: false,
      apiKeyName: originalProps.apiKeyName,
      customerId: originalProps.customerId,
      defaultCorsPreflightOptions: originalProps.defaultCorsPreflightOptions,
      defaultIntegration: originalProps.defaultIntegration,
      defaultMethodOptions: originalProps.defaultMethodOptions,
      description: originalProps.description,
      generateDistinctId: originalProps.generateDistinctId,
      resources: originalProps.resources,
      stages: originalProps.stages,
      value: originalProps.value,
    };
  }
}
python
@jsii.implements(IPropertyInjector)
class ApiKeyPropsInjector:

    def __init__(self):
        self.construct_unique_id = api.ApiKey.PROPERTY_INJECTION_ID

    def inject(self, original_props, *, scope, id):
        return api.ApiKeyProps(
            enabled=False,
            api_key_name=original_props.api_key_name,
            customer_id=original_props.customer_id,
            default_cors_preflight_options=original_props.default_cors_preflight_options,
            default_integration=original_props.default_integration,
            default_method_options=original_props.default_method_options,
            description=original_props.description,
            generate_distinct_id=original_props.generate_distinct_id,
            resources=original_props.resources,
            stages=original_props.stages,
            value=original_props.value
        )
java
public class ApiKeyPropsInjector implements IPropertyInjector {
    public final String constructUniqueId;

    public ApiKeyPropsInjector() {
        this.constructUniqueId = ApiKey.PROPERTY_INJECTION_ID;
    }

    public ApiKeyProps inject(ApiKeyProps originalProps, InjectionContext context) {
        return ApiKeyProps.builder()
                .enabled(false)
                .apiKeyName(originalProps.getApiKeyName())
                .customerId(originalProps.getCustomerId())
                .defaultCorsPreflightOptions(originalProps.getDefaultCorsPreflightOptions())
                .defaultIntegration(originalProps.getDefaultIntegration())
                .defaultMethodOptions(originalProps.getDefaultMethodOptions())
                .description(originalProps.getDescription())
                .generateDistinctId(originalProps.getGenerateDistinctId())
                .resources(originalProps.getResources())
                .stages(originalProps.getStages())
                .value(originalProps.getValue())
                .build();
    }
}
csharp
class ApiKeyPropsInjector : IPropertyInjector
{
    public string ConstructUniqueId { get; }

    public ApiKeyPropsInjector()
    {
        ConstructUniqueId = ApiKey.PROPERTY_INJECTION_ID;
    }

    public ApiKeyProps Inject(ApiKeyProps originalProps, InjectionContext context)
    {
        return new ApiKeyProps {
            Enabled = false,
            ApiKeyName = originalProps.ApiKeyName,
            CustomerId = originalProps.CustomerId,
            DefaultCorsPreflightOptions = originalProps.DefaultCorsPreflightOptions,
            DefaultIntegration = originalProps.DefaultIntegration,
            DefaultMethodOptions = originalProps.DefaultMethodOptions,
            Description = originalProps.Description,
            GenerateDistinctId = originalProps.GenerateDistinctId,
            Resources = originalProps.Resources,
            Stages = originalProps.Stages,
            Value = originalProps.Value
        };
    }
}
go
type apiKeyPropsInjector struct {
	constructUniqueId *string
}

func newApiKeyPropsInjector() *apiKeyPropsInjector {
	this := &apiKeyPropsInjector{}
	this.constructUniqueId = api.ApiKey_PROPERTY_INJECTION_ID()
	return this
}

func (this *apiKeyPropsInjector) inject(originalProps ApiKeyProps, context InjectionContext) ApiKeyProps {
	return &ApiKeyProps{
		Enabled: jsii.Boolean(false),
		ApiKeyName: originalProps.ApiKeyName,
		CustomerId: originalProps.CustomerId,
		DefaultCorsPreflightOptions: originalProps.DefaultCorsPreflightOptions,
		DefaultIntegration: originalProps.DefaultIntegration,
		DefaultMethodOptions: originalProps.DefaultMethodOptions,
		Description: originalProps.Description,
		GenerateDistinctId: originalProps.GenerateDistinctId,
		Resources: originalProps.Resources,
		Stages: originalProps.Stages,
		Value: originalProps.Value,
	}
}

Some notes:

  • ApiKey must have a PROPERTY_INJECTION_ID property, in addition to having @propertyInjectable class decorator.
  • We set ApiKeyProps.enabled to false, if it is not provided; otherwise it would use the value that was passed in.
  • It is also possible to force ApiKeyProps.enabled to false, and not provide a way for the builders to overwrite it.

Here is an example of how builders can use the injector the org created.

ts
const stack = new Stack(app, 'my-stack', {
  propertyInjectors: [new ApiKeyPropsInjector()],
});
new api.ApiKey(stack, 'my-api-key', {});
python
stack = Stack(app, "my-stack",
    property_injectors=[ApiKeyPropsInjector()]
)
api.ApiKey(stack, "my-api-key")
java
Stack stack = Stack.Builder.create(app, "my-stack")
        .propertyInjectors(List.of(new ApiKeyPropsInjector()))
        .build();
ApiKey.Builder.create(stack, "my-api-key").build();
csharp
var stack = new Stack(app, "my-stack", new StackProps {
    PropertyInjectors = new [] { new ApiKeyPropsInjector() }
});
new ApiKey(stack, "my-api-key", new ApiKeyProps { });
go
stack := awscdk.NewStack(app, jsii.String("my-stack"), &StackProps{
	PropertyInjectors: []IPropertyInjector{
		NewApiKeyPropsInjector(),
	},
})
api.NewApiKey(stack, jsii.String("my-api-key"), &ApiKeyProps{
})

This is equivalent to:

ts
const stack = new Stack(app, 'my-stack', {});
new api.ApiKey(stack, 'my-api-key', {
  enabled: false,
});
python
stack = Stack(app, "my-stack")
api.ApiKey(stack, "my-api-key",
    enabled=False
)
java
Stack stack = Stack.Builder.create(app, "my-stack").build();
ApiKey.Builder.create(stack, "my-api-key")
        .enabled(false)
        .build();
csharp
var stack = new Stack(app, "my-stack", new StackProps { });
new ApiKey(stack, "my-api-key", new ApiKeyProps {
    Enabled = false
});
go
stack := awscdk.NewStack(app, jsii.String("my-stack"), &StackProps{
})
api.NewApiKey(stack, jsii.String("my-api-key"), &ApiKeyProps{
	Enabled: jsii.Boolean(false),
})

Some notes:

  • We attach the injectors to Stack in this example, but we can also attach them to App or Stage.
  • All the ApiKey created in the scope of stack will get enabled: false.
  • Builders can overwrite the default value with new ApiKey(stack, 'my-api-key', {enabled: true});

If you specify two or more injectors for the same Constructs, the last one is in effect. In the example below, ApiKeyPropsInjector will never be applied.

ts
const stack = new Stack(app, 'my-stack', {
  propertyInjectors: [
    new ApiKeyPropsInjector(),
    new AnotherApiKeyPropsInjector(),
  ],
});
python
stack = Stack(app, "my-stack",
    property_injectors=[
        ApiKeyPropsInjector(),
        AnotherApiKeyPropsInjector()
    ]
)
java
Stack stack = Stack.Builder.create(app, "my-stack")
        .propertyInjectors(List.of(
            new ApiKeyPropsInjector(),
            new AnotherApiKeyPropsInjector()))
        .build();
csharp
var stack = new Stack(app, "my-stack", new StackProps {
    PropertyInjectors = new [] {
        new ApiKeyPropsInjector(),
        new AnotherApiKeyPropsInjector() }
});
go
stack := awscdk.NewStack(app, jsii.String("my-stack"), &StackProps{
	PropertyInjectors: []IPropertyInjector{
		NewApiKeyPropsInjector(),
		NewAnotherApiKeyPropsInjector(),
	},
})

For more information, please see the RFC.

Submodules ​

Types ​

NameKindSummary
AppConstruct (L2)A construct which represents an entire CDK app. This construct is normally the root of the construct tree.
CustomResourceConstruct (L2)Instantiation of a custom resource, whose implementation is provided a Provider.
NestedStackConstruct (L2)A CloudFormation nested stack.
ResourceConstruct (L2)An L2 construct which represents an AWS resource.
StackConstruct (L2)A root construct which represents a single CloudFormation stack.
StageConstruct (L2)An abstract application modeling unit consisting of Stacks that should be deployed together.
CfnChangeSetConstruct (L1)Resource type definition for AWS::CloudFormation::ChangeSet.
CfnCodeDeployBlueGreenHookConstruct (L1)A CloudFormation Hook for CodeDeploy blue-green ECS deployments.
CfnConditionConstruct (L1)Represents a CloudFormation condition, for resources which must be conditionally created and the determination must be made at deploy time.
CfnCustomResourceConstruct (L1)The AWS::CloudFormation::CustomResource resource creates a custom resource.
CfnElementConstruct (L1)An element of a CloudFormation stack.
CfnGeneratedTemplateConstruct (L1)Creates a generated template from existing resources using the CloudFormation IaC Generator.
CfnGuardHookConstruct (L1)The AWS::CloudFormation::GuardHook resource creates and activates a Guard Hook.
CfnHookConstruct (L1)Represents a CloudFormation resource.
CfnHookDefaultVersionConstruct (L1)The AWS::CloudFormation::HookDefaultVersion resource specifies the default version of a Hook.
CfnHookTypeConfigConstruct (L1)The AWS::CloudFormation::HookTypeConfig resource specifies the configuration of an activated Hook.
CfnHookVersionConstruct (L1)The AWS::CloudFormation::HookVersion resource publishes new or first version of a Hook to the CloudFormation registry.
CfnLambdaHookConstruct (L1)The AWS::CloudFormation::LambdaHook resource creates and activates a Lambda Hook.
CfnMacroConstruct (L1)The AWS::CloudFormation::Macro resource is a CloudFormation resource type that creates a CloudFormation macro to perform custom processing on CloudFormation templates.
CfnMappingConstruct (L1)Represents a CloudFormation mapping.
CfnModuleDefaultVersionConstruct (L1)Specifies the default version of a module.
CfnModuleVersionConstruct (L1)The AWS::CloudFormation::ModuleVersion resource registers the specified version of the module with the CloudFormation registry.
CfnOutputConstruct (L1)
CfnParameterConstruct (L1)A CloudFormation parameter.
CfnPublicTypeVersionConstruct (L1)The AWS::CloudFormation::PublicTypeVersion resource tests and publishes a registered extension as a public, third-party extension.
CfnPublisherConstruct (L1)The AWS::CloudFormation::Publisher resource registers your account as a publisher of public extensions in the CloudFormation registry.
CfnRefElementConstruct (L1)Base class for referenceable CloudFormation constructs which are not Resources.
CfnResourceConstruct (L1)Represents a CloudFormation resource.
CfnResourceDefaultVersionConstruct (L1)The AWS::CloudFormation::ResourceDefaultVersion resource specifies the default version of a resource.
CfnResourceVersionConstruct (L1)The AWS::CloudFormation::ResourceVersion resource registers a resource version with the CloudFormation registry.
CfnRuleConstruct (L1)The Rules that define template constraints in an AWS Service Catalog portfolio describe when end users can use the template and which values they can specify for parameters that are declared in the AWS CloudFormation template used to create the product they are attempting to use.
CfnStackConstruct (L1)The AWS::CloudFormation::Stack resource nests a stack as a resource in a top-level template.
CfnStackSetConstruct (L1)The AWS::CloudFormation::StackSet resource contains information about a StackSet.
CfnTypeActivationConstruct (L1)The AWS::CloudFormation::TypeActivation resource activates a public third-party extension, making it available for use in stack templates.
CfnWaitConditionConstruct (L1)The AWS::CloudFormation::WaitCondition resource provides a way to coordinate stack resource creation with configuration actions that are external to the stack creation or to track the status of a configuration process.
CfnWaitConditionHandleConstruct (L1)The AWS::CloudFormation::WaitConditionHandle type has no properties.
AcknowledgmentStructAn acknowledgment of a validation rule, used to suppress it from output.
AddDockerImageAssetOptionsStructOptions for the addDockerImageAsset operation.
AddFileAssetOptionsStructOptions for the addFileAsset operation.
AnnotationsClassIncludes API for attaching annotations such as warning messages to constructs.
AppPropsStructInitialization props for apps.
ArnClass
ArnComponentsStruct
ArnFormatEnumAn enum representing the various ARN formats that different services use.
ArrayMergeStrategyClassStrategies for merging arrays in L1 property mixins.
AspectApplicationClassObject respresenting an Aspect application.
AspectOptionsStructOptions when Applying an Aspect.
AspectPriorityClassDefault Priority values for Aspects.
AspectsClassAspects can be applied to CDK tree scopes and can operate on the tree before synthesis.
AssetHashTypeEnumThe type of asset hash.
AssetManifestBuilderClassBuild an asset manifest from assets added to a stack.
AssetManifestDockerImageDestinationStructThe destination for a docker image asset, when it is given to the AssetManifestBuilder.
AssetManifestFileDestinationStructThe destination for a file asset, when it is given to the AssetManifestBuilder.
AssetOptionsStructAsset hash options.
AssetStagingConstructStages a file or directory from a location on the file system into a staging directory.
AssetStagingPropsStructInitialization properties for AssetStaging.
AwsClassAccessor for pseudo parameters.
AWSEventMetadataPropsStructProperties for AWS EventBridge event metadata.
BitrateClassRepresents a bitrate value.
BootstraplessSynthesizerClassSynthesizer that reuses bootstrap roles from a different region.
BootstraplessSynthesizerPropsStructConstruction properties of BootstraplessSynthesizer.
BundlingFileAccessEnumThe access mechanism used to make source files available to the bundling container and to return the bundling output back to the host.
BundlingOptionsStructBundling options.
BundlingOutputEnumThe type of output that a bundling operation is producing.
CfnAutoScalingInstanceRefreshStructTo specify how AWS CloudFormation handles instance refresh for an Auto Scaling group, use the AutoScalingInstanceRefresh update policy.
CfnAutoScalingInstanceRefreshAlarmSpecificationStructAlarm specification for the AutoScalingInstanceRefresh update policy.
CfnAutoScalingInstanceRefreshPreferencesStructPreferences for the AutoScalingInstanceRefresh update policy.
CfnAutoScalingReplacingUpdateStructSpecifies whether an Auto Scaling group and the instances it contains are replaced during an update.
CfnAutoScalingRollingUpdateStructTo specify how AWS CloudFormation handles rolling updates for an Auto Scaling group, use the AutoScalingRollingUpdate policy.
CfnAutoScalingScheduledActionStructWith scheduled actions, the group size properties of an Auto Scaling group can change at any time.
CfnCapabilitiesEnumCapabilities that affect whether CloudFormation is allowed to change IAM resources.
CfnChangeSet.TagsItemsPropertyStruct
CfnChangeSetPropsStructProperties for defining a CfnChangeSet.
CfnCodeDeployBlueGreenAdditionalOptionsStructAdditional options for the blue/green deployment.
CfnCodeDeployBlueGreenApplicationStructThe application actually being deployed.
CfnCodeDeployBlueGreenApplicationTargetStructType of the CfnCodeDeployBlueGreenApplication.target property.
CfnCodeDeployBlueGreenEcsAttributesStructThe attributes of the ECS Service being deployed.
CfnCodeDeployBlueGreenHookPropsStructConstruction properties of CfnCodeDeployBlueGreenHook.
CfnCodeDeployBlueGreenLifecycleEventHooksStructLifecycle events for blue-green deployments.
CfnCodeDeployLambdaAliasUpdateStructTo perform an AWS CodeDeploy deployment when the version changes on an AWS::Lambda::Alias resource, use the CodeDeployLambdaAliasUpdate update policy.
CfnConditionPropsStruct
CfnCreationPolicyStructAssociate the CreationPolicy attribute with a resource to prevent its status from reaching create complete until AWS CloudFormation receives a specified number of success signals or the timeout period is exceeded.
CfnCustomResourcePropsStructProperties for defining a CfnCustomResource.
CfnDeletionPolicyEnumWith the DeletionPolicy attribute you can preserve or (in some cases) backup a resource when its stack is deleted.
CfnDynamicReferenceClassReferences a dynamically retrieved value.
CfnDynamicReferencePropsStructProperties for a Dynamic Reference.
CfnDynamicReferenceServiceEnumThe service to retrieve the dynamic reference from.
CfnGeneratedTemplate.TemplateConfigurationPropertyStructThe configuration details of the generated template.
CfnGeneratedTemplate.TemplateProgressPropertyStructA summary of the progress of the template generation.
CfnGeneratedTemplatePropsStructProperties for defining a CfnGeneratedTemplate.
CfnGuardHook.HookTargetPropertyStructHook targets are the destination where hooks will be invoked against.
CfnGuardHook.OptionsPropertyStructSpecifies the input parameters for a Guard Hook.
CfnGuardHook.S3LocationPropertyStructSpecifies the S3 location where your Guard rules or input parameters are located.
CfnGuardHook.StackFiltersPropertyStructThe StackFilters property type specifies stack level filters for a Hook.
CfnGuardHook.StackNamesPropertyStructSpecifies the stack names for the StackFilters property type to include or exclude specific stacks from Hook invocations.
CfnGuardHook.StackRolesPropertyStructSpecifies the stack roles for the StackFilters property type to include or exclude specific stacks from Hook invocations based on their associated IAM roles.
CfnGuardHook.TargetFiltersPropertyStructThe TargetFilters property type specifies the target filters for the Hook.
CfnGuardHookPropsStructProperties for defining a CfnGuardHook.
CfnHookDefaultVersionPropsStructProperties for defining a CfnHookDefaultVersion.
CfnHookPropsStructConstruction properties of CfnHook.
CfnHookTypeConfigPropsStructProperties for defining a CfnHookTypeConfig.
CfnHookVersion.LoggingConfigPropertyStructThe LoggingConfig property type specifies logging configuration information for an extension.
CfnHookVersionPropsStructProperties for defining a CfnHookVersion.
CfnJsonConstructCaptures a synthesis-time JSON object a CloudFormation reference which resolves during deployment to the resolved values of the JSON object.
CfnJsonPropsStruct
CfnLambdaHook.HookTargetPropertyStructHook targets are the destination where hooks will be invoked against.
CfnLambdaHook.LoggingConfigPropertyStructContains logging configuration information for an extension.
CfnLambdaHook.StackFiltersPropertyStructThe StackFilters property type specifies stack level filters for a Hook.
CfnLambdaHook.StackNamesPropertyStructSpecifies the stack names for the StackFilters property type to include or exclude specific stacks from Hook invocations.
CfnLambdaHook.StackRolesPropertyStructSpecifies the stack roles for the StackFilters property type to include or exclude specific stacks from Hook invocations based on their associated IAM roles.
CfnLambdaHook.TargetFiltersPropertyStructThe TargetFilters property type specifies the target filters for the Hook.
CfnLambdaHookPropsStructProperties for defining a CfnLambdaHook.
CfnMacroPropsStructProperties for defining a CfnMacro.
CfnMappingPropsStruct
CfnModuleDefaultVersionPropsStructProperties for defining a CfnModuleDefaultVersion.
CfnModuleVersionPropsStructProperties for defining a CfnModuleVersion.
CfnOutputPropsStruct
CfnParameterPropsStruct
CfnPublicTypeVersionPropsStructProperties for defining a CfnPublicTypeVersion.
CfnPublisherPropsStructProperties for defining a CfnPublisher.
CfnResourceAutoScalingCreationPolicyStructFor an Auto Scaling group replacement update, specifies how many instances must signal success for the update to succeed.
CfnResourceDefaultVersionPropsStructProperties for defining a CfnResourceDefaultVersion.
CfnResourcePropsStruct
CfnResourceSignalStructWhen AWS CloudFormation creates the associated resource, configures the number of required success signals and the length of time that AWS CloudFormation waits for those signals.
CfnResourceVersion.LoggingConfigPropertyStructLogging configuration information for a resource.
CfnResourceVersionPropsStructProperties for defining a CfnResourceVersion.
CfnRuleAssertionStructA rule assertion.
CfnRulePropsStructA rule can include a RuleCondition property and must include an Assertions property.
CfnStack.OutputPropertyStructThe Output data type.
CfnStackPropsStructProperties for defining a CfnStack.
CfnStackSet.AutoDeploymentPropertyStructDescribes whether StackSets automatically deploys to AWS Organizations accounts that are added to a target organization or organizational unit (OU).
CfnStackSet.DeploymentTargetsPropertyStructThe AWS Organizations accounts or AWS accounts to deploy stacks to in the specified Regions.
CfnStackSet.ManagedExecutionPropertyStructDescribes whether StackSets performs non-conflicting operations concurrently and queues conflicting operations.
CfnStackSet.OperationPreferencesPropertyStructThe user-specified preferences for how CloudFormation performs a StackSet operation.
CfnStackSet.ParameterPropertyStructThe Parameter data type.
CfnStackSet.StackInstancesPropertyStructStack instances in some specific accounts and Regions.
CfnStackSetPropsStructProperties for defining a CfnStackSet.
CfnTagStruct
CfnTrafficRouteStructA traffic route, representing where the traffic is being directed to.
CfnTrafficRoutingStructType of the CfnCodeDeployBlueGreenEcsAttributes.trafficRouting property.
CfnTrafficRoutingConfigStructTraffic routing configuration settings.
CfnTrafficRoutingTimeBasedCanaryStructThe traffic routing configuration if CfnTrafficRoutingConfig.type is CfnTrafficRoutingType.TIME_BASED_CANARY.
CfnTrafficRoutingTimeBasedLinearStructThe traffic routing configuration if CfnTrafficRoutingConfig.type is CfnTrafficRoutingType.TIME_BASED_LINEAR.
CfnTrafficRoutingTypeEnumThe possible types of traffic shifting for the blue-green deployment configuration.
CfnTypeActivation.LoggingConfigPropertyStructContains logging configuration information for an extension.
CfnTypeActivationPropsStructProperties for defining a CfnTypeActivation.
CfnUpdatePolicyStructUse the UpdatePolicy attribute to specify how AWS CloudFormation handles updates to the AWS::AutoScaling::AutoScalingGroup resource.
CfnWaitConditionHandlePropsStructProperties for defining a CfnWaitConditionHandle.
CfnWaitConditionPropsStructProperties for defining a CfnWaitCondition.
CliCredentialsStackSynthesizerClassA synthesizer that uses conventional asset locations, but not conventional deployment roles.
CliCredentialsStackSynthesizerPropsStructProperties for the CliCredentialsStackSynthesizer.
CloudFormationValidatePluginClassValidation plugin that uses the CloudFormation validation engine to evaluate templates against built-in rules.
CloudFormationValidatePluginPropsStructProperties for configuring the CloudFormationValidatePlugin.
CombineStrategyOptionsStructOptions for the combine strategy.
ConstructSelectorClassSelects constructs from a construct tree based on various criteria.
ContextProviderClassBase class for the model side of context providers.
CopyOptionsStructOptions applied when copying directories.
CrossStackReferencesClassErgonomic API for configuring cross-stack reference strength on a construct.
CustomResourcePropsStructProperties to provide a Lambda-backed custom resource.
CustomResourceProviderConstructAn AWS-Lambda backed custom resource provider, for CDK Construct Library constructs.
CustomResourceProviderBaseConstructBase class for creating a custom resource provider.
CustomResourceProviderBasePropsStructInitialization properties for CustomResourceProviderBase.
CustomResourceProviderOptionsStructInitialization options for custom resource providers.
CustomResourceProviderPropsStructInitialization properties for CustomResourceProvider.
CustomResourceProviderRuntimeEnumThe lambda runtime to use for the resource provider.
DefaultStackSynthesizerClassUses conventionally named roles and asset storage locations.
DefaultStackSynthesizerPropsStructConfiguration properties for DefaultStackSynthesizer.
DefaultTokenResolverClassDefault resolver implementation.
DockerBuildOptionsStructDocker build options.
DockerBuildSecretClassMethods to build Docker CLI arguments for builds using secrets.
DockerCacheOptionStructOptions for configuring the Docker cache backend.
DockerIgnoreStrategyClassIgnores file paths based on the .dockerignore specification.
DockerImageClassA Docker image.
DockerImageAssetLocationStructThe location of the published docker image.
DockerImageAssetSourceStruct
DockerRunOptionsStructDocker run options.
DockerVolumeStructA Docker volume.
DockerVolumeConsistencyEnumSupported Docker volume consistency types.
DurationClassRepresents a length of time.
EncodingOptionsStructProperties to string encodings.
EncryptedPermissionsOptionsStructOptions for configuring permissions on encrypted resources.
EnvironmentStructThe deployment environment for a stack.
ErrorsClassHelper to check if an error is of a certain type.
ExpirationClassRepresents a date of expiration.
ExportValueOptionsStructOptions for the stack.exportValue() method.
FeatureFlagsClassFeatures that are implemented behind a flag in order to preserve backwards compatibility for existing apps.
FileAssetLocationStructThe location of the published file asset.
FileAssetPackagingEnumPackaging modes for file assets.
FileAssetSourceStructRepresents the source for a file asset.
FileCopyOptionsStructOptions applied when copying directories into the staging location.
FileFingerprintOptionsStructOptions related to calculating source hash.
FileSystemClassFile system utilities.
FingerprintOptionsStructOptions related to calculating source hash.
FnClassCloudFormation intrinsic functions.
GetContextKeyOptionsStruct
GetContextKeyResultStruct
GetContextValueOptionsStruct
GetContextValueResultStruct
GitIgnoreStrategyClassIgnores file paths based on the .gitignore specification.
GlobIgnoreStrategyClassIgnores file paths based on simple glob patterns.
IAnyProducerInterfaceInterface for lazy untyped value producers.
IArrayMergeStrategyInterfaceInterface for merging arrays.
IAspectInterfaceRepresents an Aspect.
IAssetInterfaceCommon interface for all assets.
IBoundStackSynthesizerInterfaceA Stack Synthesizer, obtained from IReusableStackSynthesizer..
ICfnConditionExpressionInterfaceRepresents a CloudFormation element that can be used within a Condition.
ICfnResourceOptionsInterface
ICfnRuleConditionExpressionInterfaceInterface to specify certain functions as Service Catalog rule-specific.
IConstructSelectorInterfaceSelects constructs from a construct tree.
IFragmentConcatenatorInterfaceFunction used to concatenate symbols in the target document language.
IgnoreModeEnumDetermines the ignore behavior to use.
IgnoreStrategyClassRepresents file path ignoring behavior.
IInspectableInterfaceInterface for examining a construct and exposing metadata.
IListProducerInterfaceInterface for lazy list producers.
ILocalBundlingInterfaceLocal bundling.
IMergeStrategyInterfaceInterface for applying properties to a target using a specific strategy.
InjectionContextStructThis defines the values needed for Injection.
IntrinsicClassToken subclass that represents values intrinsic to the target document language.
IntrinsicPropsStructCustomization properties for an Intrinsic token.
INumberProducerInterfaceInterface for lazy number producers.
IPolicyValidationContextInterfaceContext available to the validation plugin.
IPolicyValidationContextBeta1InterfaceContext available to the validation plugin.
IPolicyValidationPluginInterfaceRepresents a validation plugin that will be executed during synthesis.
IPolicyValidationPluginBeta1InterfaceRepresents a validation plugin that will be executed during synthesis.
IPostProcessorInterfaceA Token that can post-process the complete resolved value, after resolve() has recursed over it.
IPropertyInjectorInterfaceThis interface define an inject function that operates on a Construct's Property.
IResolvableInterfaceInterface for values that can be resolvable later.
IResolveContextInterfaceCurrent resolution context for tokens.
IResourceInterfaceInterface for L2 Resource constructs.
IReusableStackSynthesizerInterfaceInterface for Stack Synthesizers that can be used for more than one stack.
IStableAnyProducerInterfaceInterface for (stable) lazy untyped value producers.
IStableListProducerInterfaceInterface for (stable) lazy list producers.
IStableNumberProducerInterfaceInterface for (stable) lazy number producers.
IStableStringProducerInterfaceInterface for (stable) lazy string producers.
IStackSynthesizerInterfaceEncodes information how a certain Stack should be deployed.
IStringProducerInterfaceInterface for lazy string producers.
ISynthesisSessionInterfaceRepresents a single session of synthesis.
ITaggableInterfaceInterface to implement tags.
ITaggableV2InterfaceModernized version of ITaggable.
ITemplateOptionsInterfaceCloudFormation template options for a stack.
ITokenMapperInterfaceInterface to apply operation to tokens in a string.
ITokenResolverInterfaceHow to resolve tokens.
JsonNullClassAn object which serializes to the JSON null literal, and which can safely be passed across languages where undefined and null are not different.
LazyClassLazily produce a value.
LazyAnyValueOptionsStructOptions for creating lazy untyped tokens.
LazyListValueOptionsStructOptions for creating a lazy list token.
LazyStringValueOptionsStructOptions for creating a lazy string token.
LegacyStackSynthesizerClassUse the CDK classic way of referencing assets.
MissingRemovalPoliciesClassManages removal policies for resources without existing policies within a construct scope.
MixinClassAbstract base class for mixins that provides default implementations.
MixinApplicationStructRepresents a successful mixin application.
MixinApplicatorClassApplies mixins to constructs.
MixinsClassMain entry point for applying mixins.
NamesClassFunctions for devising unique names for constructs.
NestedStackPropsStructInitialization props for the NestedStack construct.
NestedStackSynthesizerClassSynthesizer for a nested stack.
PermissionsBoundaryClassApply a permissions boundary to all IAM Roles and Users within a specific scope.
PermissionsBoundaryBindOptionsStructOptions for binding a Permissions Boundary to a construct scope.
PermissionsOptionsStructOptions for configuring permissions in the &lt;Resource&gt;.actions() method.
PhysicalNameClassIncludes special markers for automatic generation of physical names.
PolicyValidationPluginReportStructThe report emitted by the plugin after evaluation.
PolicyValidationPluginReportBeta1StructThe report emitted by the plugin after evaluation.
PolicyValidationReportStatusEnumThe final status of the validation report.
PolicyValidationReportStatusBeta1EnumThe final status of the validation report.
PolicyValidationStackStructInformation about a single stack that is being validated.
PolicyViolatingResourceStructResource violating a specific rule.
PolicyViolatingResourceBeta1StructResource violating a specific rule.
PolicyViolationStructViolation produced by the validation plugin.
PolicyViolationBeta1StructViolation produced by the validation plugin.
PropertyInjectorsClassThis is a collection of ProjectInjectors assigned to this scope.
PropertyMergeStrategyClassStrategy for handling nested properties in L1 property mixins.
ReferenceClassAn intrinsic Token that represents a reference to a construct.
ReferenceStrengthEnumControls how cross-stack references to a resource are resolved.
RemovalPoliciesClassManages removal policies for all resources within a construct scope, overriding any existing policies by default.
RemovalPolicyEnumPossible values for a resource's Removal Policy.
RemovalPolicyOptionsStruct
RemovalPolicyPropsStructProperties for applying a removal policy.
RemoveTagClassThe RemoveTag Aspect will handle removing tags from this node and children.
ResolutionTypeHintEnumType hints for resolved values.
ResolveChangeContextOptionsStructOptions that can be changed while doing a recursive resolve.
ResolveOptionsStructOptions to the resolve() operation.
ResourcePropsStructConstruction properties for Resource.
ReverseOptionsStructOptions for the 'reverse()' operation.
RoleOptionsStructOptions for specifying a role.
ScopedAwsClassAccessor for scoped pseudo parameters.
SecretsManagerSecretOptionsStructOptions for referencing a secret value from Secrets Manager.
SecretValueClassWork with secret values in the CDK.
ShimsClassConverts between Mixins and Aspects.
SizeClassRepresents the amount of digital storage.
SizeConversionOptionsStructOptions for how to convert time to a different unit.
SizeRoundingBehaviorEnumRounding behaviour when converting between units of Size.
StackPropsStruct
StackSynthesizerClassBase class for implementing an IStackSynthesizer.
StagePropsStructInitialization props for a stage.
StageSynthesisOptionsStructOptions for assembly synthesis.
StringConcatClassConverts all fragments to strings and concats those.
SymlinkFollowModeEnumDetermines how symlinks are followed.
SynthesizeStackArtifactOptionsStructStack artifact options.
TagClassThe Tag Aspect will handle adding a tag to this node and cascading tags to children.
TagManagerClassTagManager facilitates a common implementation of tagging for Constructs.
TagManagerOptionsStructOptions to configure TagManager behavior.
TagPropsStructProperties for a tag.
TagsClassManages AWS tags for all resources within a construct scope.
TagTypeEnum
TimeConversionOptionsStructOptions for how to convert time to a different unit.
TimeZoneClassCanonical names of the IANA time zones, derived from the IANA Time Zone Database.
TokenClassRepresents a special or lazily-evaluated value.
TokenComparisonClassAn enum-like class that represents the result of comparing two Tokens.
TokenizationClassLess oft-needed functions to manipulate Tokens.
TokenizedStringFragmentsClassFragments of a concatenated string containing stringified Tokens.
TreeInspectorClassInspector that maintains an attribute bag.
UniqueResourceNameOptionsStructOptions for creating a unique resource name.
ValidationResultClassRepresentation of validation results.
ValidationResultsClassA collection of validation results.
ValidationRuleSourceStructA custom rule source for the validation engine.
ValidationsClassManages validations for CDK constructs.