Speed up CDK deployments with this one simple trick!

| 3 min read

Introduction

(Sorry for the clickbait title, but I just couldn't resist ๐Ÿ˜…)

Recently, when looking at CDK's changelog, I've noticed this gem released in v2.44.0. From my previous work on Serverless Framework, I know how slow changeset-based deployments can be and how much time we can save if we switch to direct CloudFormation stack updates. Let's see how we can do that!

Prerequisites

CDK in version 2.44.0 or higher is required. If you don't have CDK installed and setup, please refer to official documentation. In the rest of the article I will assume that you're familiar with CDK, and have it installed and configured.

Project setup

In our case, we will use a simple example from official example repository with an API, a few Lambda functions, and DynamoDB. You can find the example under the following address: https://github.com/aws-samples/aws-cdk-examples/tree/master/typescript/api-cors-lambda-crud-dynamodb.

After cloning the repository, let's navigate to the project directory:

cd aws-cdk-examples/typescript/api-cors-lambda-crud-dynamodb

Then, we will build our project:

npm install && npm run build

and perform the initial deployment:

cdk deploy

Deploying changes to our project

Now that we have our initial project deployed, let's see how much time does it take to deploy a simple code change. Let's create a simple lambdas/util.ts file, that will simulate a shared library that is used by all functions in our project:

export const util = () => console.log('Hello, world!')

Then, let's import that util in all of our functions and invoke it inside handler body, below see an example how get-all.ts looks like after our changes:

import * as AWS from 'aws-sdk';
import { util } from './util';

const TABLE_NAME = process.env.TABLE_NAME || '';

const db = new AWS.DynamoDB.DocumentClient();

export const handler = async (): Promise<any> => {
util()

const params = {
TableName: TABLE_NAME
};

console.log('Something else');

try {
const response = await db.scan(params).promise();
return { statusCode: 200, body: JSON.stringify(response.Items) };
} catch (dbError) {
return { statusCode: 500, body: JSON.stringify(dbError) };
}
};

In the next step, let's deploy our project again and see how much time did it take to deploy this change:

cdk deploy

In my case, after testing it multiple times, the average deployment time reported by CDK was around 70 seconds.

Speeding up the deployments

So, the 70 seconds for deployment isn't too bad, but let's see if we can improve it, by taking advantage of direct stack updates. To do so, we only need to add a simple --method=direct flag to our command. Let's do a small change in util.ts so it now looks like this:

export const util = () => console.log('Hello, direct deployment!')

and try to deploy our project once again, this time with direct update:

cdk deploy --method=direct

In my case, once again after testing it multiple times, the average deployment time reported by CDK was around 37 seconds. That's almost 2x speedup for our simple case!

How does that work

By default, the CDK uses change set functionality to perform CloudFormation stack updates. However, if you don't inspect the change set manually before deploying it, there's a very high chance that you don't need to use change sets at all. Maybe you don't even know that you were using them! By adding flag --method=direct, we instruct the CDK to skip change set creation and to instead update the CloudFormation stack directly. That single operation very often takes much less time than two operations of creating and then applying the change set to your stack. There's one visible downside to using direct update - you will no longer see a nice progress bar in the output of cdk deploy command, but I believe it's a small price to pay for saving a lot of time on your deployments.

Summary

In this short blog post we've learned how we can greatly speed up the CDK deployments with a simple flag added to cdk deploy command. Of course, before using that, make sure that you're not relying on change set functionality in any way. In our example, we were able to achieve ~30 seconds reduction in the deployment time, but when implementing similar feature in Serverless Framework, I've seen multiple reports from people that were able to reduce their deployment time from 10 to 5 minutes. I think that this seemingly small change can translate to many computing hours saved across all the CDK projects being deployed every day.

Thanks for reading and see you next time! ๐Ÿ‘‹