Authoring Custom Constructs
Relevant source files
The following files were used as context for generating this wiki page:- design/construct-tree.md
- packages/@aws-cdk/example-construct-library/README.md
- README.md
- packages/@aws-cdk/cfnspec/build-tools/create-missing-libraries.ts
- packages/@aws-cdk/custom-resources/package.json
- packages/@aws-cdk/aws-codebuild/package.json
- packages/@aws-cdk/example-construct-library/package.json
Custom constructs are the fundamental building blocks of AWS Cloud Development Kit (CDK) applications. They allow developers to define reusable cloud components using high-level, object-oriented abstractions in modern programming languages. A construct can represent a single AWS resource or a complex, multi-resource component with encapsulated logic and best practices. Authoring custom constructs is key to creating scalable and maintainable infrastructure as code.
Sources: README.md:16-21, design/construct-tree.md:13-18
This document outlines the architecture, structure, and best practices for creating custom construct libraries within the AWS CDK framework, based on the project's design documents and existing library examples.
The Construct Tree
All CDK applications are composed into a hierarchy of constructs known as the "construct tree". This tree starts with the App at its root, which contains one or more Stacks. Each stack, in turn, contains the constructs that define the AWS resources. The CDK synthesizes this tree into a Cloud Assembly, which includes AWS CloudFormation templates and other assets.
A key goal is to expose this construct tree as a tree.json artifact within the Cloud Assembly. This provides a structured, machine-readable representation of the application's components, their properties, and their relationships, which is invaluable for debugging, visualization, and building developer tools.
Sources: design/construct-tree.md:5-7, 13-14, 95-98
The following diagram illustrates the basic hierarchy of a CDK application.
This diagram shows the hierarchical nature of a CDK application, from the root App down to individual CloudFormation resources encapsulated within constructs.
tree.json Data Model
During cdk synth, the CDK core module generates a tree.json file in the cdk.out directory. This file contains the data model for the entire construct tree. The root of the JSON object contains a tree property, which is a map of constructs indexed by their paths.
The structure of the tree.json file is designed to be extensible.
{
"version": "tree-0.1",
"tree": {
"id": "App",
"path": "",
"children": {
"mystack": {
"path": "mystack",
"children": {
"mycfnresource": {
"path": "mystack/mycfnresource",
"attributes": {
"aws:cdk:props": {
"mystringpropkey": "mystringpropval"
}
}
},
"mytopic": {
"path": "mystack/mytopic",
"attributes": {
"aws:cdk:cloudformation:type": "AWS::SNS::Topic",
"aws:cdk:cloudformation:properties": {
"DisplayName": "MyTopic"
}
}
}
}
}
}
}
}
Source: design/construct-tree.md:130-161
Construct Properties in tree.json
Each node in the tree has a defined set of properties that describe the construct.
| Property | Type | Required | Source | Description |
|---|---|---|---|---|
path | string | Required | construct.node.path | The full, absolute path of the construct within the tree. |
children | Array | Not Required | construct.node.children | An array of absolute paths to the direct children of this construct. |
attributes | Array | Not Required | construct.node.attributes | A key-value map of arbitrary metadata associated with the construct. |
Source: design/construct-tree.md:104-111
Providing Construct Metadata
Construct authors can contribute custom metadata to the tree.json file by implementing the ITreeAttributes interface. This allows constructs to report configured values, documentation links, or any other relevant context.
/***
* Information that a construct will contribute towards the construct tree*
* such as dependencies, properties, links, documentation, etc
*/
export interface ITreeAttributes {
// attributes will be added to the construct tree
readonly attributes: [key: string]: string;
}
Source: design/construct-tree.md:166-174
Attributes should be namespaced to avoid conflicts. For example, L1 CloudFormation resources use the aws:cdk:cloudformation namespace for their type and properties.
Source: design/construct-tree.md:121-124
Construct Library Structure
A construct library is an installable package (e.g., on npm, PyPI, Maven) that contains one or more custom constructs. The CDK repository provides a template and tooling for creating new libraries.
Source: packages/@aws-cdk/example-construct-library/README.md:10-15
Package Definition (package.json)
The package.json file is the heart of a construct library. It defines the package name, version, dependencies, build scripts, and JSII configuration for multi-language support.
Key sections of a typical construct library package.json:
| Section | Description |
|---|---|
name | The name of the package, typically following the pattern @aws-cdk/aws-servicename. |
jsii | Configuration for JSII, the technology that enables writing TypeScript code and publishing it for use in other languages like Python, Java, .NET, and Go. |
scripts | Build-related commands like build, test, lint, and package. These are often standardized using cdk-build-tools. |
cdk-build | Specifies the CloudFormation namespace (e.g., AWS::CodeBuild) that the library models, enabling automated generation of L1 constructs. |
dependencies | Runtime dependencies, which must include @aws-cdk/core and constructs. |
peerDependencies | Specifies dependencies that the consumer of the library is expected to provide. This typically mirrors the dependencies list. |
stability | Indicates the stability of the module, such as experimental or stable. |
Sources: packages/@aws-cdk/aws-codebuild/package.json, packages/@aws-cdk/example-construct-library/package.json, packages/@aws-cdk/custom-resources/package.json
Automated Library Creation
The CDK repository includes a script to automatically scaffold new construct library packages for CloudFormation namespaces that don't yet have one. This tool generates the entire package structure, including package.json, .gitignore, README.md, and initial TypeScript files.
The following diagram shows the process of generating a new library.
This flowchart depicts the logic within create-missing-libraries.ts for scaffolding new construct libraries.
Source: packages/@aws-cdk/cfnspec/build-tools/create-missing-libraries.ts:15-62
Example Library
The @aws-cdk/example-construct-library serves as a template for authors. It demonstrates the recommended code structure, including:
- How to define a high-level (L2) construct.
- The use of a
privatedirectory for internal helper functions. - Examples of unit and integration tests.
The README for this example package is the recommended starting point for new construct authors.
Source: packages/@aws-cdk/example-construct-library/README.md:10-15, 42-44
Special-Purpose Constructs
Custom Resources
For scenarios where CloudFormation does not natively support a resource or action, the CDK provides constructs for creating AWS CloudFormation Custom Resources. The @aws-cdk/custom-resources package contains the necessary building blocks. These constructs typically involve an AWS Lambda function that implements the create, update, and delete logic for the custom resource.
The package.json for this module shows its dependencies on core modules like @aws-cdk/aws-lambda, @aws-cdk/aws-iam, and @aws-cdk/core.
Source: packages/@aws-cdk/custom-resources/package.json:61-68
Summary
Authoring custom constructs is a powerful feature of the AWS CDK that promotes reuse, enforces best practices, and simplifies the definition of complex cloud infrastructure. By following the established patterns for library structure and leveraging the construct tree metadata, developers can create high-quality, multi-language components. The tree.json artifact, in particular, opens up possibilities for enhanced tooling, providing deeper insights into the application's structure and behavior directly from the developer's IDE.
Sources: design/construct-tree.md:46-51, 95-98, README.md:16-21