Setting Up a CDK Project

Scaffolding a Node and TypeScript AWS CDK project for a notes CRUD API: project structure, the Stack class, and the synth-bootstrap-deploy flow.

September 6, 20264 min read

This section builds a small CRUD API for a notes app: create a note, read one, update one, delete one. API Gateway accepts the HTTP request, a Lambda function handles it, and DynamoDB stores the data.

The infrastructure for all of that gets defined with AWS CDK, not by clicking through the console. CDK turns TypeScript code into a CloudFormation template, and CloudFormation is what actually creates the resources on AWS.

CDK is not the SDK

Both are npm packages. Both have "AWS" in the name. They solve two completely different problems, and it's worth being precise about this before writing a single line of either.

SDK stands for Software Development Kit, a generic term for any package that lets your code talk to some system without you writing the raw plumbing by hand. The AWS SDK is that, specifically for AWS: a set of packages (@aws-sdk/client-dynamodb, @aws-sdk/client-s3, and so on) that let your code call an AWS service that already exists.

  • CDK runs once, at deploy time, to create resources. A DynamoDB table, a Lambda function, an API Gateway, none of them exist yet until cdk deploy runs.
  • The SDK runs later, at runtime, inside a Lambda's own code, every single time it's invoked. It reads or writes to a resource that CDK already created.

Here's the SDK, used inside a Lambda handler to write to a DynamoDB table:

TypeScript
import { DynamoDBClient, PutItemCommand } from "@aws-sdk/client-dynamodb"; const client = new DynamoDBClient({}); await client.send(new PutItemCommand({ TableName: "Notes", Item: { id: { S: "123" }, text: { S: "buy milk" } }, }));

CDK builds the house. The SDK is what the app uses to live in it. This post is entirely about CDK, creating the Notes table in the first place. The SDK code above never appears anywhere near a CDK stack file, it only shows up once the Lambda functions themselves get written, later in this chapter.

Installing CDK

Bash
npm install -g aws-cdk

The CDK CLI is the tool that reads your code and turns it into a deployment. Installing it globally is normal here, unlike a project dependency, it's a command you run from anywhere, not code your app imports.

Scaffolding the project

Bash
mkdir node-notes-crud-api && cd node-notes-crud-api cdk init app --language typescript

cdk init app creates a new CDK project from a template. --language typescript picks TypeScript over the other supported languages (Python, Java, C#, Go). That one command produces a working, if empty, CDK app.

What the scaffold actually creates

  • bin/node-notes-crud-api.ts — the entry point. It creates one instance of your stack and tells CDK which AWS account and region to deploy it to.
  • lib/node-notes-crud-api-stack.ts — the actual infrastructure. This is where Lambda functions, the API Gateway, and the DynamoDB table get defined, as TypeScript, inside a class that extends CDK's Stack.
  • cdk.json — tells the CDK CLI how to run your app (which command turns your TypeScript into the app CDK reads).
  • package.json / tsconfig.json — a normal Node and TypeScript project underneath all of this. CDK is a library (aws-cdk-lib), not a separate runtime.
  • test/ — a starter unit test file, using CDK's assertions library to check the generated CloudFormation template matches expectations.

The Stack class, in short

Every resource, the DynamoDB table, each Lambda function, the API Gateway, gets declared inside the stack's constructor. A stack is one unit of deployment: everything inside it gets created, updated, or destroyed together, as one CloudFormation stack.

TypeScript
export class NodeNotesCrudApiStack extends cdk.Stack { constructor(scope: Construct, id: string, props?: cdk.StackProps) { super(scope, id, props); // Resources get declared here: a DynamoDB table, // Lambda functions, an API Gateway REST API. } }

Nothing is deployed yet at this point, this class only describes what should exist.

Three commands, three different jobs

  1. cdk synth — compiles the TypeScript stack into an actual CloudFormation template (JSON/YAML) and prints it. No AWS account is touched. Useful for checking what CDK is about to create before it creates it.
  2. cdk bootstrap — a one-time setup per AWS account and region. It creates a small set of CDK-owned resources (an S3 bucket for deployment assets, mainly) that every future cdk deploy in that account depends on.
  3. cdk deploy — synthesizes the stack, then actually creates or updates the real AWS resources by handing the CloudFormation template to CloudFormation itself.

Bootstrap runs once per account and region. Synth and deploy run every time the stack changes.

The Essentials

  1. CDK code doesn't deploy anything by itself. It compiles to a CloudFormation template; CloudFormation does the actual work.
  2. A stack is the unit of deployment. Everything declared inside one gets created, updated, or torn down together.
  3. cdk bootstrap runs once per account and region, before the first deploy. Skipping it is the most common reason a first cdk deploy fails.

Further Reading and Watching