AWS CDK in C# is a powerful way to define your cloud infrastructure as code, but it doesn’t directly compile to CloudFormation.

Let’s see it in action. Imagine you want to create a simple S3 bucket. In C#, you’d write something like this:

using Amazon.CDK;
using Amazon.CDK.AWS.S3;
using Constructs;

public class MyCdkStack : Stack
{
    public MyCdkStack(Construct scope, string id, IStackProps props = null) : base(scope, id, props)
    {
        // The code that defines your stack goes here
        var bucket = new Bucket(this, "MyFirstBucket", new BucketProps
        {
            BucketName = "my-unique-cdk-bucket-name-12345", // Must be globally unique
            RemovalPolicy = RemovalPolicy.DESTROY, // Careful with this in production!
            AutoDeleteObjects = true // Also careful!
        });

        // Output the bucket name
        new CfnOutput(this, "BucketNameOutput", new CfnOutputProps
        {
            Value = bucket.BucketName,
            Description = "The name of the S3 bucket created by CDK"
        });
    }
}

When you run cdk synth from your project directory, the CDK Toolkit takes this C# code, compiles it into an intermediate representation, and then generates an AWS CloudFormation template. This template is what actually gets deployed to your AWS account. The cdk synth command is your window into this process, showing you the raw CloudFormation JSON or YAML that will be provisioned.

The core problem the CDK solves is the verbosity and imperative nature of traditional AWS infrastructure provisioning. Instead of clicking through the AWS console or writing complex, state-managing imperative scripts, you declare your desired state in a familiar programming language. The CDK handles the translation to CloudFormation, ensuring idempotency and consistency. Internally, the CDK uses a tree of "Constructs." A Construct is the basic building block in the CDK. It represents a cloud component, which can be as simple as a single AWS resource (like an S3 bucket) or as complex as an entire application stack (like a VPC with EC2 instances and load balancers). When you instantiate a Bucket in the C# code above, you’re creating an S3 Bucket Construct. The CDK’s synthesis process walks this tree of constructs and generates the corresponding CloudFormation resources.

When you define a resource like an S3 bucket, you interact with its Props (properties). These are C# objects that mirror the configuration options available in CloudFormation. For example, BucketName, RemovalPolicy, and AutoDeleteObjects directly map to CloudFormation properties for an AWS::S3::Bucket resource. The this keyword in new Bucket(this, ...) refers to the parent construct, building the hierarchical structure of your infrastructure. The id parameter ("MyFirstBucket") is a logical ID used within the CDK application to refer to this specific construct, and it also forms part of the physical resource name in CloudFormation.

A common point of confusion is the RemovalPolicy. When set to DESTROY, it tells the CDK that this resource should be deleted when the stack is deleted. For S3 buckets, this is crucial because CloudFormation cannot delete a non-empty bucket. AutoDeleteObjects = true is a CDK convenience that ensures the bucket is emptied before deletion, but it’s essential to understand that RemovalPolicy.DESTROY on a bucket with data means that data will be lost upon stack deletion. This is why it’s often recommended to use RemovalPolicy.RETAIN for critical resources in production environments.

The CDK doesn’t just create resources; it also allows you to define outputs. The CfnOutput construct, as shown in the example, exposes values from your stack, such as the bucket name, to be easily retrieved after deployment or used as inputs for other stacks. These outputs are also generated as Outputs in the CloudFormation template.

The underlying CloudFormation generation is handled by the CDK’s "CloudAssembly" concept. When you run cdk synth, the C# code is compiled, and the CDK constructs are evaluated to produce a CloudAssembly, which is a directory containing the CloudFormation templates and other metadata. The cdk deploy command then takes this CloudAssembly and uses the AWS CloudFormation service to provision your infrastructure.

A subtle but powerful aspect of CDK is the concept of "Aspects." Aspects allow you to apply transformations or checks across your entire construct tree. For instance, you could write an aspect to ensure all S3 buckets have versioning enabled or to enforce specific tagging policies on all resources. You apply an aspect using Aspects.Of(this).Add(new MyCustomAspect()) within your stack definition, and it will be evaluated during synthesis, affecting the generated CloudFormation.

The next thing you’ll likely want to explore is how to manage multiple stacks within a single CDK application and how to deploy them independently.

Want structured learning?

Take the full Cdk course →