Publishing a CDK construct library to npm is surprisingly straightforward once you understand how the AWS CDK packaging system uses standard Node.js tooling under the hood.
Let’s see a construct library in action. Imagine we’ve written a simple construct that provisions an S3 bucket with versioning enabled.
// my-construct-lib/lib/my-s3-bucket.ts
import { Construct } from 'constructs';
import * as s3 from 'aws-cdk-lib/aws-s3';
import { Stack, StackProps } from 'aws-cdk-lib';
export interface MyS3BucketProps extends s3.BucketProps {
// You can add custom props here if needed
}
export class MyS3Bucket extends Construct {
public readonly bucket: s3.Bucket;
constructor(scope: Construct, id: string, props: MyS3BucketProps) {
super(scope, id);
this.bucket = new s3.Bucket(this, 'Resource', {
...props, // Spread the incoming props
versioned: true, // Enforce versioning
});
}
}
Now, let’s say we want to publish this to npm so others can use it.
The core of publishing a CDK construct library relies on jsii (JavaScript Interoperability) and standard npm packaging. jsii allows you to write your construct in TypeScript (or other .NET languages) and compile it into multiple language targets, including JavaScript. This JavaScript output is what gets published to npm.
Here’s the typical workflow:
-
Project Setup: You’ll have a standard TypeScript project. Your
package.jsonwill havejsiias a dev dependency, along with@aws-cdk/core(oraws-cdk-libin newer versions) andconstructs.// package.json { "name": "my-construct-library", "version": "0.1.0", "description": "A sample CDK construct library", "main": "lib/index.js", "types": "lib/index.d.ts", "jsii": { "outdir": "lib", "targets": "jsii-targets", "tsc": "tsc", "excludeTypesPackage": false }, "scripts": { "build": "jsii", "package": "jsii-pack", "publish": "npm publish" }, "dependencies": { "constructs": "^10.0.0", "aws-cdk-lib": "^2.0.0" }, "devDependencies": { "jsii": "^5.0.0", "jsii-pac": "^5.0.0", "typescript": "^4.0.0" } }The
jsiiconfiguration block is crucial.outdirspecifies where the compiled JavaScript and type definitions will go.targetsis wherejsiiwill place the output for various languages (though we’re focusing on the npm package, which is the JavaScript output).tscpoints to the TypeScript compiler. -
Compilation: The
jsiiCLI is responsible for compiling your TypeScript code into JavaScript. It also generates the necessary metadata for other language targets. Runningnpm run build(which executesjsii) will create thelibdirectory containingindex.js,index.d.ts, and other necessary files. -
Packaging:
jsii-packis the tool that takes the compiled output fromjsiiand bundles it into a ready-to-publish npm package. It creates a.jsiifile containing metadata and ensures the correct files are included in the package. Runningnpm run packageexecutesjsii-pack. -
Publishing: Once packaged, you can publish to npm using the standard
npm publishcommand. Ensure you’re logged into npm (npm login) with an account that has publish rights to the desired package name. Runningnpm run publishwill upload your construct library.A common mistake is forgetting to run
jsii-packbeforenpm publish. This will result in a package that contains your source TypeScript but not the compiled JavaScript that Node.js requires, leading to import errors when others try to use your construct.# After running `npm run build` npm run package npm publish
The most surprising thing about publishing a CDK construct library is that you don’t need to do anything particularly "CDK-specific" after you’ve written your constructs. The magic of interoperability and packaging is handled by jsii and standard npm tooling. You’re essentially publishing a well-structured JavaScript library that happens to be designed for use within the AWS CDK ecosystem.
When someone installs your published construct library (npm install my-construct-library), their Node.js environment will be able to require() or import your constructs directly because the jsii output is standard JavaScript. The aws-cdk-lib and constructs dependencies in your package.json ensure that the runtime environment has the necessary base classes and types available.
The next step after publishing is typically to create a sample usage repository to demonstrate how your construct can be integrated into a CDK application.