This documentation is for the developer preview release of the AWS CDK. Do not use this version of the AWS CDK in production. Subsequent releases of the AWS CDK will likely include breaking changes.

Tutorial: Creating an AWS CDK Application

This topic walks you through creating and deploying an AWS CDK app, by using the cdk init command, as described in the Creating a Project from the Template section, or manually, as described in the Creating a Project Manually section.

In either case, the first step is to create the directory for your project, with an empty Git repository. All of these instructions use this directory:

mkdir hello-cdk
cd hello-cdk
git init

Creating a Project from the Template

In this section we use the cdk init command to create a skeleton project from a template in any of the supported languages.

Initializing the Project

Run the cdk init command to initialize an empty project. The AWS CDK contains templates for all of the supported languages. To create an empty (no AWS resources in the resulting AWS CloudFormation stack), run the following command, where LANGUAGE is one of the supported programming languages: csharp (C#), java (Java), or typescript (TypeScript).

cdk init --language LANGUAGE

Compiling the Project

If needed, compile the code:

Compile the code using your IDE or via the dotnet CLI:

dotnet build
No need to compile

To compile your program from .ts to .js:

npm run build

You can also use the watch command to continuously compile your code as it changes, so you don’t have to invoke the compiler explicitly:

# run in another terminal session
npm run watch

Compile your code using your IDE or via the command line via mvn:

mvn compile

You have now created your first AWS CDK app. The next section creates a similar app manually, so you can skip it and continue with the Listing the Stacks in the App section.

Creating a Project Manually

In this section we create a new AWS CDK project using explicit command-line commands. Be sure to navigate to the hello-cdk directory before you start.

Initializing the Project

Create an empty project for the AWS CDK app.

Create a new console application.

dotnet new console

Create an initial npm package.json file:

npm init -y # creates package.json

Create a .gitignore file with the following content:

*.js
node_modules

Create an initial npm package.json file:

npm init -y # creates package.json

Create a .gitignore file with the following content:

*.js
*.d.ts
node_modules

Add the build and watch TypeScript commands to package.json:

{
    "scripts": {
        "build": "tsc",
        "watch": "tsc -w"
    }
}

Create a minimal tsconfig.json:

{
    "compilerOptions": {
        "target": "es2018",
        "module": "commonjs"
    }
}

Create a minimal cdk.json (this saves you from including –app node bin/hello-cdk.js in every cdk command):

{
    "app": "node bin/hello-cdk.js"
}

Create a .gitignore file with the following content:

.classpath.txt
target
.classpath
.project
.idea
.settings
.vscode
*.iml

Use your favorite IDE to create a Maven-based empty Java 8 project.

Set the Java source and target to 1.8 in your pom.xml file:

<!-- pom.xml -->
<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.1</version>
            <configuration>
                <source>1.8</source>
                <target>1.8</target>
            </configuration>
        </plugin>
    </plugins>
</build>

Adding the CDK Core as a Dependency

Install the AWS CDK core library (@aws-cdk/cdk) This library includes the basic classes needed to write AWS CDK stacks and apps.

Install the Amazon.CDK NuGet package:

dotnet add package Amazon.CDK

Install the @aws-cdk/cdk package:

npm install @aws-cdk/cdk

Install the @aws-cdk/cdk package:

npm install @aws-cdk/cdk

Add the following to your project’s pom.xml file:

<dependencies>
    <dependency>
        <groupId>software.amazon.awscdk</groupId>
        <artifactId>cdk</artifactId>
        <version><!-- cdk-version --></version>
    </dependency>
</dependencies>

Defining the AWS CDK App

AWS CDK apps are classes that extend the App class. Create an empty App:

In Program.cs

using Amazon.CDK;

namespace HelloCdk
{
    class Program
    {
        static void Main(string[] args)
        {
            var myApp = new App();
            myApp.Run();
        }
    }
}

Create the file bin/hello-cdk.js:

const cdk = require('@aws-cdk/cdk');

class MyApp extends cdk.App {
    constructor() {
        super();
    }
}

new MyApp().run();

Create the file bin/hello-cdk.ts:

import cdk = require('@aws-cdk/cdk');
import { HelloCdkStack } from '../lib/hello-cdkstack';

const app = new cdk.App();
new HelloCdkStack(app, 'HelloCdkStack');
app.run();

Create the file lib/hello-cdkstack.ts:

import cdk = require('@aws-cdk/cdk');

export class HelloCdkStack extends cdk.Stack {
    constructor(parent: cdk.App, name: string, props?: cdk.StackProps) {
        super(parent, name, props);

        // The code that defines your stack goes here
    }
}

In src/main/java/com/acme/MyApp.java:

package com.acme;

import software.amazon.awscdk.App;

import java.util.Arrays;

public class MyApp {
    public static void main(final String argv[]) {
        App app = new App();

        app.run();
    }
}

Compiling the Code

If needed, compile the code:

Compile the code using your IDE or via the dotnet CLI:

dotnet build
No need to compile

To compile your program from .ts to .js:

npm run build

You can also use the watch command to continuously compile your code as it changes, so you don’t have to invoke the compiler explicitly:

# run in another terminal session
npm run watch

Compile your code using your IDE or via the command line via mvn:

mvn compile

You have now created your first AWS CDK app.

Listing the Stacks in the App

Use the AWS CDK toolkit’s ls command to list the stacks in the app.

cdk ls

The result is just the name of the stack:

HelloCdkStack

Note

There is a known issue on Windows with the AWS CDK .NET environment. Whenever you use a cdk command, it issues a node warning similar to the following:

(node:27508) UnhandledPromiseRejectionWarning: Unhandled promise rejection
(rejection id: 1): Error: EPIPE: broken pipe, write
(node:27508) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated.
In the future, promise rejections that are not handled will terminate the
Node.js process with a non-zero exit code.

You can safely ignore this warning.

Define a Stack

Define a stack and add it to the app.

Create MyStack.cs:

using Amazon.CDK;

namespace HelloCdk
{
    public class MyStack: Stack
    {
        public MyStack(App parent, string name) : base(parent, name, null)
        {
        }
    }
}

In Program.cs:

using Amazon.CDK;

namespace HelloCdk
{
    class Program
    {
        static void Main(string[] args)
        {
            var myApp = new App();
            new MyStack(myApp, "hello-cdk");
            myApp.Run();
        }
    }
}

In index.js:

const cdk = require('@aws-cdk/cdk');

class MyStack extends cdk.Stack {
    constructor(parent, id, props) {
        super(parent, id, props);
    }
}

class MyApp extends cdk.App {
    constructor(argv) {
        super(argv);

        new MyStack(this, 'hello-cdk');
    }
}

new MyApp().run();
Nothing to do.

In src/main/java/com/acme/MyStack.java:

package com.acme;

import software.amazon.awscdk.App;
import software.amazon.awscdk.Stack;
import software.amazon.awscdk.StackProps;

public class MyStack extends Stack {
    public MyStack(final App parent, final String name) {
        this(parent, name, null);
    }

    public MyStack(final App parent, final String name, final StackProps props) {
        super(parent, name, props);
    }
}

In src/main/java/com/acme/MyApp.java:

package com.acme;

import software.amazon.awscdk.App;
import java.util.Arrays;

public class MyApp {
    public static void main(final String argv[]) {
        App app = new App();

        new MyStack(app, "hello-cdk");

        app.run();
    }
}

The initializer signature of cdk.Stack includes the arguments: parent, id, and props. This is the signature for every class in the AWS CDK framework. These classes are called “constructs” and they are composed together into a tree:

  • parent represents the parent construct. By specifying the parent construct upon initialization, constructs can obtain contextual information when they are initialized. For example, the region a stack is deployed to can be obtained via a call to Stack.find(this).requireRegion(). See Environmental Context for more information.
  • id is a string that locally identifies this construct within the tree. Constructs must have a unique ID amongst their siblings.
  • props is the set of initialization properties for this construct.

Compile your program:

We configured cdk.json to run dotnet run, which restores dependencies, builds, and runs your application, run cdk.

cdk
Nothing to compile.
npm run build
mvn compile

Define an Amazon S3 Bucket

Now, what can we do with this app? Nothing yet. Our stack is still empty, so there’s nothing to deploy.

Let’s define an Amazon S3 bucket.

Install the @aws-cdk/aws-s3 package:

dotnet add package Amazon.CDK.AWS.S3
npm install @aws-cdk/aws-s3
npm install @aws-cdk/aws-s3

Edit your pom.xml file:

<dependency>
    <groupId>software.amazon.awscdk</groupId>
    <artifactId>s3</artifactId>
    <version><!-- cdk-version --></version>
</dependency>

Next, define an Amazon S3 bucket in the stack. Amazon S3 buckets are represented by the Bucket class:

Create MyStack.cs:

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

namespace HelloCdk
{
    public class MyStack : Stack
    {
        public MyStack(App parent, string name) : base(parent, name, null)
        {
            new Bucket(this, "MyFirstBucket", new BucketProps
            {
                Versioned = true
            });
        }
    }
}

In index.js:

const cdk = require('@aws-cdk/cdk');
const s3 = require('@aws-cdk/aws-s3');

class MyStack extends cdk.Stack {
    constructor(parent, id, props) {
        super(parent, id, props);

        new s3.Bucket(this, 'MyFirstBucket', {
            versioned: true
        });
    }
}

In lib/:

import cdk = require('@aws-cdk/cdk');
import s3 = require('@aws-cdk/aws-s3');

export class HelloCdkStack extends cdk.Stack {
    constructor(parent: cdk.App, id: string, props?: cdk.StackProps) {
        super(parent, id, props);

        new s3.Bucket(this, 'MyFirstBucket', {
            versioned: true
        });
    }
}

In src/main/java/com/acme/MyStack.java:

package com.acme;

import software.amazon.awscdk.App;
import software.amazon.awscdk.Stack;
import software.amazon.awscdk.StackProps;
import software.amazon.awscdk.services.s3.Bucket;
import software.amazon.awscdk.services.s3.BucketProps;

public class MyStack extends Stack {
    public MyStack(final App parent, final String name) {
        this(parent, name, null);
    }

    public MyStack(final App parent, final String name, final StackProps props) {
        super(parent, name, props);

        new Bucket(this, "MyFirstBucket", BucketProps.builder()
                .withVersioned(true)
                .build());
    }
}

A few things to notice:

  • Bucket is a construct. This means it’s initialization signature has parent, id, and props. In this case, the bucket is an immediate child of MyStack.
  • MyFirstBucket is the logical id of the bucket construct, not the physical name of the S3 bucket. The logical ID is used to uniquely identify resources in your stack across deployments. See Logical IDs for more details on how to work with logical IDs. To specify a physical name for your bucket, you can set the bucketName property when you define your bucket.
  • Since the bucket’s versioned property is true, versioning is enabled on the bucket.

Compile your program:

We configured cdk.json to run dotnet run, which restores dependencies, builds, and runs your application, run cdk.
Nothing to compile.
npm run build
mvn compile

Synthesize an AWS CloudFormation Template

Synthesize a AWS CloudFormation template for the stack:

cdk synth HelloCdkStack

Note

Since the AWS CDK app only contains a single stack, you can omit HelloCdkStack.

This command executes the AWS CDK app and synthesize an AWS CloudFormation template for the HelloCdkStack stack. You should see something similar to the following, where VERSION is the version of the AWS CDK.

Resources:
  MyFirstBucketB8884501:
    Type: AWS::S3::Bucket
    Properties:
      VersioningConfiguration:
        Status: Enabled
    Metadata:
      aws:cdk:path: HelloCdkStack/MyFirstBucket/Resource
  CDKMetadata:
    Type: AWS::CDK::Metadata
    Properties:
      Modules: "@aws-cdk/aws-codepipeline-api=VERSION,@aws-cdk/aws-events=VERSION,@aws-c\
        dk/aws-iam=VERSION,@aws-cdk/aws-kms=VERSION,@aws-cdk/aws-s3=VERSION,@aws-c\
        dk/aws-s3-notifications=VERSION,@aws-cdk/cdk=VERSION,@aws-cdk/cx-api=VERSION\
        .0,hello-cdk=0.1.0"

You can see that the stack contains an AWS::S3::Bucket resource with the desired versioning configuration.

Note

The AWS::CDK::Metadata resource was automatically added to your template by the toolkit. This allows us to learn which libraries were used in your stack. See version_reporting for more details and how to opt-out.

Deploying the Stack

Use cdk deploy to deploy the stack:

cdk deploy

The deploy command synthesizes an AWS CloudFormation template from the stack and then invokes the AWS CloudFormation create/update API to deploy it into your AWS account. The command displays information as it progresses.

Modifying the Code

Configure the bucket to use KMS managed encryption:

new Bucket(this, "MyFirstBucket", new BucketProps
{
    Versioned = true,
    Encryption = BucketEncryption.KmsManaged
});
new s3.Bucket(this, 'MyFirstBucket', {
    versioned: true,
    encryption: s3.BucketEncryption.KmsManaged
});
new s3.Bucket(this, 'MyFirstBucket', {
    versioned: true,
    encryption: s3.BucketEncryption.KmsManaged
});
new Bucket(this, "MyFirstBucket", BucketProps.builder()
        .withVersioned(true)
        .withEncryption(BucketEncryption.KmsManaged)
        .build());

Compile the program:

We configured cdk.json to run dotnet run, which restores dependencies, builds, and runs your application, run cdk.
Nothing to compile.
npm run build
mvn compile

Preparing for Deployment

Before you deploy the updated stack, use the cdk diff command to evaluate the difference between the AWS CDK app and the deployed stack:

cdk diff

The toolkit queries your AWS account for the current AWS CloudFormation template for the hello-cdk stack, and compares the result with the template synthesized from the app. The output should look like the following:

[~] 🛠 Updating MyFirstBucketB8884501 (type: AWS::S3::Bucket)
└─ [+] .BucketEncryption:
    └─ New value: {"ServerSideEncryptionConfiguration":[{"ServerSideEncryptionByDefault":{"SSEAlgorithm":"aws:kms"}}]}

As you can see, the diff indicates that the ServerSideEncryptionConfiguration property of the bucket is now set to enable server-side encryption.

You can also see that the bucket is not going to be replaced but rather updated (“Updating MyFirstBucketB8884501”).

Run cdk deploy to update the stack:

cdk deploy

The toolkit updates the bucket configuration to enable server-side KMS encryption for the bucket:

⏳  Starting deployment of stack hello-cdk...
[0/2] UPDATE_IN_PROGRESS  [AWS::S3::Bucket] MyFirstBucketB8884501
[1/2] UPDATE_COMPLETE     [AWS::S3::Bucket] MyFirstBucketB8884501
[1/2] UPDATE_COMPLETE_CLEANUP_IN_PROGRESS  [AWS::CloudFormation::Stack] hello-cdk
[2/2] UPDATE_COMPLETE     [AWS::CloudFormation::Stack] hello-cdk
✅  Deployment of stack hello-cdk completed successfully

What Next?