aws-cdk-lib
aws-cdk-lib is the AWS Cloud Development Kit v2 construct library for defining AWS infrastructure in TypeScript or JavaScript and synthesizing it into CloudFormation. It puts the core framework and constructs for AWS services into one versioned package. You build an `App`, organize resources into `Stack` and reusable `Construct` classes, inspect the generated template with the separate CDK CLI, and deploy through AWS CloudFormation. Higher-level L2 and L3 constructs supply defaults and convenience methods; generated L1 constructs expose the underlying CloudFormation resources.
The default choice for TypeScript teams committed to AWS and CloudFormation, especially when L2 constructs remove large amounts of IAM and integration boilerplate. Do not mistake concise code for simple infrastructure: inspect the synthesized template and diff every deployment.
Use it if
- Your infrastructure is mostly or entirely on AWS and CloudFormation is an acceptable deployment engine
- Your team wants to define infrastructure with TypeScript control flow, types, tests, and reusable construct classes
- You value higher-level AWS patterns such as permission grants, event targets, and service integrations over writing raw CloudFormation
- You need one CDK v2 dependency instead of the many per-service packages used by CDK v1
- You need one workflow across several cloud providers: aws-cdk-lib is built around AWS services and synthesizes CloudFormation, while Pulumi or CDK for Terraform fits multi-cloud estates better
- You want a small dependency: version 2.263.0 has an unpacked size of 128,012,674 bytes and 7,228 files because every stable AWS construct ships in one library
- Your team prefers reviewing explicit declarative resources: high-level constructs can synthesize IAM roles, policies, custom resources, Lambda handlers, and defaults that are not obvious from the few lines of application code
- You cannot tolerate release-level API risk in new service modules: the README says Experimental modules may make breaking changes in any release, while only Stable modules follow semantic versioning
- You do not want AWS account bootstrapping, credentials, context caching, asset publishing roles, and CloudFormation deployment behavior in the development loop
Setup reality
The library and the command-line tool are separate. A TypeScript app needs Node.js 20 or newer, `aws-cdk-lib`, and the required `constructs` peer at ^10.5.0; install `aws-cdk` as a project development dependency so CI and developers run the same CLI. `cdk init` creates `cdk.json`, TypeScript configuration, an app entry point, tests, and scripts, but an existing project must supply an `app` command in `cdk.json` itself. Synthesis can run without deploying, yet context lookups such as `Vpc.fromLookup` contact AWS and cache results in `cdk.context.json`; commit that file when reproducible templates matter. Deployment needs AWS credentials with permission to assume the bootstrap roles and create the resources in your stacks. Each target account and region normally needs a one-time `cdk bootstrap`, which creates an S3 asset bucket, ECR repository, IAM roles, and related resources. Lambda code, Docker images, and file deployments add local asset staging; Docker or an external bundler may be required depending on the construct. Environment-agnostic stacks cannot perform account or region lookups, so pass `CDK_DEFAULT_ACCOUNT` and `CDK_DEFAULT_REGION` or fixed values when needed. Always run `cdk synth` and `cdk diff` in CI before `cdk deploy`, and remember that deletions, replacements, IAM expansions, and retained resources are CloudFormation operations with real cost and data-loss consequences. The project also collects anonymous operational metrics by default and links to an official opt-out guide.
Patterns
Install the library, peer, and local CLIinstall-cdk-v2
npm install aws-cdk-lib@2.263.0 constructs@^10.5.0
npm install --save-dev aws-cdk@^2aws-cdk-lib is the construct library; the separate aws-cdk package provides synth, diff, bootstrap, and deploy commands.
Create an environment-specific stackdefine-app-stack
import {App, Stack} from 'aws-cdk-lib';
const app = new App();
const stack = new Stack(app, 'OrdersStack', {
env: {
account: process.env.CDK_DEFAULT_ACCOUNT,
region: process.env.CDK_DEFAULT_REGION,
},
});
app.synth();An explicit environment enables account and region lookups but makes the synthesized stack environment-specific.
Create a private versioned S3 bucketcreate-secure-bucket
import {RemovalPolicy} from 'aws-cdk-lib';
import * as s3 from 'aws-cdk-lib/aws-s3';
const bucket = new s3.Bucket(stack, 'Documents', {
blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL,
encryption: s3.BucketEncryption.S3_MANAGED,
enforceSSL: true,
versioned: true,
removalPolicy: RemovalPolicy.RETAIN,
});RETAIN protects data when the stack is deleted, but it also leaves the bucket and its charges for you to clean up manually.
Package a Lambda function from a directorycreate-lambda-function
import * as lambda from 'aws-cdk-lib/aws-lambda';
const handler = new lambda.Function(stack, 'Handler', {
runtime: lambda.Runtime.NODEJS_22_X,
handler: 'index.handler',
code: lambda.Code.fromAsset('lambda'),
environment: {TABLE_NAME: 'orders'},
});Code.fromAsset stages and uploads the directory during deployment; compile TypeScript and exclude unnecessary files before synthesis.
Put API Gateway in front of Lambdaexpose-lambda-api
import * as apigateway from 'aws-cdk-lib/aws-apigateway';
const api = new apigateway.LambdaRestApi(stack, 'OrdersApi', {
handler,
proxy: false,
});
api.root.addResource('orders').addMethod('GET');With proxy false, define resources and methods explicitly; CDK also creates the Lambda invoke permission.
Create an on-demand DynamoDB tablecreate-dynamodb-table
import * as dynamodb from 'aws-cdk-lib/aws-dynamodb';
const table = new dynamodb.Table(stack, 'Orders', {
partitionKey: {name: 'id', type: dynamodb.AttributeType.STRING},
billingMode: dynamodb.BillingMode.PAY_PER_REQUEST,
pointInTimeRecoverySpecification: {
pointInTimeRecoveryEnabled: true,
},
removalPolicy: RemovalPolicy.RETAIN,
});A retained table survives stack deletion; changing a key schema later generally requires resource replacement.
Grant a function least-privilege table accessgrant-resource-access
table.grantReadWriteData(handler);
handler.addEnvironment('TABLE_NAME', table.tableName);Grant helpers attach IAM statements to the function role and are safer than spelling broad service actions by hand.
Reference an existing S3 bucketimport-existing-resource
const logs = s3.Bucket.fromBucketName(
stack,
'ExistingLogs',
'company-central-logs',
);
logs.grantRead(handler);An imported construct is a reference, not ownership; deleting the CDK stack does not delete the existing bucket.
Look up a VPC from the target accountlookup-existing-vpc
import * as ec2 from 'aws-cdk-lib/aws-ec2';
const vpc = ec2.Vpc.fromLookup(stack, 'Vpc', {
tags: {Environment: 'production'},
});Lookups need an explicit stack environment and AWS credentials, and their result is cached in cdk.context.json.
Expose a deployment outputadd-stack-output
import {CfnOutput} from 'aws-cdk-lib';
new CfnOutput(stack, 'ApiUrl', {
value: api.url,
description: 'Orders API base URL',
});Outputs are visible through CloudFormation and the CLI; never place passwords or secret values in them.
Apply tags through a stacktag-construct-tree
import {Tags} from 'aws-cdk-lib';
Tags.of(stack).add('Environment', 'production');
Tags.of(stack).add('Owner', 'platform');Tags propagate to taggable descendants, but not every AWS resource type supports every tag behavior.
Test synthesized CloudFormationassert-template
import {App} from 'aws-cdk-lib';
import {Template} from 'aws-cdk-lib/assertions';
const app = new App();
const stack = new OrdersStack(app, 'TestStack');
const template = Template.fromStack(stack);
template.hasResourceProperties('AWS::S3::Bucket', {
VersioningConfiguration: {Status: 'Enabled'},
});Assertions inspect the synthesized template, so they catch infrastructure output changes rather than only construct object behavior.
Alternatives
| Package | Registry | Pick it when |
|---|---|---|
| @pulumi/aws | npm | You want TypeScript infrastructure with Pulumi state and a consistent model across cloud providers |
| cdktf | npm | You prefer Terraform providers and state but still want to author infrastructure with TypeScript constructs |
| sst | npm | You are building an AWS application and want a more opinionated developer workflow around functions, frontends, and local development |