CDK constructs are a great way to combine best practices and simplify your infrastructure code. Have you ever written your own CDK construct? Writing a construct is easy using the CDK CLI. But soon you’ll discover the hard parts: Keeping all dependencies updated; Aligning the CDK dependency versions to not have version conflicts; And publishing your CDK construct to multiple repositories. projen
makes the CDK construct setup and maintenance a lot easier. And jsii
helps to release your TypeScript CDK construct to Java, Python and C#. Here is a short tutorial about migrating a CDK construct to projen and jsii.
I have provided a beginner’s step-by-step guide about getting started with projen and jsii. This will help you exploring typical options for projen and explains the process of publishing your CDK Construct to repositories like NPM, Maven, PyPi, and NuGet using jsii. I recommend to read it if you have no prior experience with projen or jsii.
About projen and jsii
projen is a tool to write your project configuration using code instead of managing it yourself. It was created to help you writing CDK constructs. You only define your project configuration in a .projenrc.js file and it will generate your project files for you. This includes a package.json
and other configuration files for eslint
or GitHub Actions. It is designed to automate all the boring project setup steps.
jsii is the technology behind the AWS CDK that allows you to write CDK Constructs in TypeScript/JavaScript and compile them to other languages like Java or Python. There’s a good AWS blog post about how it works.
Setup Your Construct Project
Let’s start to migrate your existing CDK Construct to projen. You have probably created your CDK construct using the following cdk
command:
cd my-cdk-construct
cdk init lib --language=typescript
That command creates various folders and files with pre-defined defaults writing a CDK construct using TypeScript. For example, it initializes your project with a lib
and test
folder as well as an example construct file and a related test file. Finally, you can run your tests using Jest with npm run test
. This is the basis of the next steps, even though you might have added further lib files, tests or tools like ESLint or similar.
Please note that you can only use projen
and jsii
with TypeScript/JavaScript as the source language at the moment. This means, you can not create a CDK construct in Java and publish it to NPM.
Migrating Your CDK Construct to projen
💡 Before you start migrating your CDK construct to projen, you might want to open this blog post about converting your CDK construct to using projen by Matthew Bonig in another browser tab. His article also covers some interesting facts and small errors he has experienced in the process, so they might help you as well.
Before you execute any command, make sure you have a clean Git status. This ensures that you can easily revert any undesired changes.
The following commands will initialize your project with projen
. It will create a file called .projenrc.js
containing a default projen
configuration. Then it will automatically execute this file for you to generate further files and folders based on your projen
configuration:
cd my-cdk-construct
npx projen new awscdk-construct
After executing the commands, you’ll see lots of changes in your Git status. For example, projen
expects source files in src
whereas a CDK construct initialized via the CDK CLI expects them to live in lib
. Also, there will be a folder called .projen
containing configuration files for projen
. You don’t need to look into all of the new files immediately. projen
is managing the contents of files like GitHub Actions or TypeScript configurations based on the settings you define in .projenrc.js
.
Updating Your Project Files with projen
After migrating your CDK construct to projen
, you should always follow this process to update project files generated by projen
:
- Make according changes in
.projenrc.js
. - Run
npx projen
andprojen
will synthesize the changes to all project files. 💡 Hint: create an alias likepj
in your command line to avoid typingnpx projen
over and over again. - Never manually edit the generated files because
projen
will overwrite them the next time!
If you have used tools like eslint
or Dependabot before, you’ll probably see changes in their related files as well. If you don’t like the defaults, you can always change the settings in .projenrc.js
. However, you’ll probably don’t have to change that much since projen is applying common settings for eslint. I only noticed two changes compared to my settings: include an uppercase ‘i’ (= I) in interface names and make its properties readonly. Everything else was just related to some minor style adjustments.
💡 Since I don’t know all varieties of CDK construct setups, you might run into other errors after adding projen
. If you have any problems you can’t solve by yourself, feel free to reach out to me or send your question to the CDK developers Slack.
Important General Settings
Now it’s a good time to have a look at the most important settings you can set in .projenrc.js
. I’ll outline them below and explain them in case it’s not too obvious.
Setting | Description |
projectType | Define if this project is a library or app. For a library (i.e. CDK construct), you should use ProjectType.LIB . |
packageManager | Define which package manager you want to use, e.g. Yarn or NPM. Set the value like NodePackageManager.NPM . |
cdkVersion | With this property you are defining the CDK version you want to use for all CDK dependencies. Due to the nature of CDK, it’s important to align the numbers. |
cdkDependencies | Enter all the CDK dependencies that you are using in your construct. You probably had them defined in your package.json file before but now you need to add them here. Add them like ['@aws-cdk/core', '...'] . Since you specify the CDK version with cdkVersion , you don’t need to set it here. |
bundledDeps | List of dependencies you want to bundle with your construct. This might be necessary in case you use some constructs like NodejsFunction for a Lambda function. It will build your Lambda function’s code only when the Lambda function is used in a CDK stack. And then those dependencies need to be available. |
deps | Any other regular dependencies that your construct is using. |
peerDeps | A list of peer dependencies. projen will automatically add all @aws-cdk dependencies to the list of peer dependencies, so you don’t need to define them here. But you can add any other dependencies here that you’d like to have in the resulting peerDependencies of the package.json file. |
packageName | By default, projen will take the name property as the name in package.json . However, it might be necessary to overwrite it here. |
gitignore, npmignore | Should be self explanatory. You can define a list of strings matching files or folders you’d like to ignore for Git or NPM. |
Important: Don’t forget to run npx projen
each time you make a change in .projenrc.js
. Otherwise projen
won’t synthesize the config changes to your project files.
Release Settings
You have to consider that by default projen
assumes you want to publish your CDK construct to NPM. Hence, it sets up GitHub Actions that perform the relevant tasks for you, like bundling, running the tests and releasing the artifact. If you want to skip this for now, consider adjusting the following settings:
Setting | Description |
releaseBranches | A list of branch names. The default is ['main'] but you can adjust it to whatever branches you need. If you set this to an empty array, then you can only trigger a release by manually starting the release workflow (in case you enabled to add a release workflow, see below). |
releaseEveryCommit | If set to true and a commit is added on any of the branches defined in releaseBranches , then a release is triggered. |
releaseSchedule | Optional: cron expression to regularly release a new version. |
releaseToNpm | If a new version should be released to NPM using GitHub Actions. |
releaseWorkflow | If you want to have a release workflow using GitHub Actions. |
Again, don’t forget to run npx projen
to update your project files after changing the projen
settings in .projenrc.js
.
Location of Lambda Function Code
In case you are creating a Lambda function in your CDK construct, you might wonder where you should put your Lambda function code and how you bundle it. When using projen
, I’d say a good approach is to keep all the Lambda function code in a subfolder next to your CDK construct source files. For example, the code could go into src/lambda
. This ensures that projen
picks up the files and includes them in the artifact that’s being released to NPM. You can read my other blog post if you want to know more ways about how to bundle your Lambda function code in a CDK construct.
Building Your Construct
Now that you have finally adjusted the necessary projen
settings and fixed any code or linting issues, you can verify that your code compiles. You can use commands like npm run build
or npm run test
to verify your code. (Use Yarn
instead if you kept projen
‘s default setting of packageManager
) Is your code compiling? Great! If not, did you forget anything or did I miss to cover anything here? Let me know about it!
After a green build, you are ready to commit your changes and push them to your remote Git repository. Then, the GitHub actions configured under .github/actions
will trigger and build (+ release) your CDK construct 🚀
Custom Build or Workflow Steps
Before migrating your CDK construct to projen
, you probably had some custom scripts or commands in your project. For example, you prepared certain things for a Lambda function or your CDK construct in general. With projen
you can add custom build and workflow steps as well. Here is how you can do it in .projenrc.js
:
const project = new AwsCdkConstructLibrary({...});
// add a build step:
project.buildTask.exec('echo "Hello World"');
// add a job to the GitHub Action file of release.yml:
project.releaseWorkflow.addJobs({
example: {
name: 'Example Job',
'runs-on': 'ubuntu-latest',
steps: [{...}],
},
});
As soon as update the project files by running npx projen
again, you’ll see changes in .projen/tasks.json
and .github/actions/release.yml
.
Publishing to Multiple Repositories Using jsii
After you have finally migrated your code, it’s time to add some magic to your CDK construct. The magic comes by a combination of projen
and jsii
. Their biggest advantage is that you can make your CDK construct available not only to NPM but also Maven, PyPi and NuGet by just setting a few settings.
As described above, projen
provides a few release settings. Use them to publish your CDK construct to NPM. If you want to publish your CDK construct to Maven, PyPi or NuGet, then consider the following settings:
Setting | Repository | Description |
publishToMaven | Maven | Allows you to configure the Java package, group id and artifact id. |
publishToPypi | PyPi | Allows you to configure the dist name and module. |
publishToNuget | NuGet | Allows you to configure the namespace and package id. |
Enabling these settings (and running npx projen
again 😉) will create appropriate steps in the release.yml
GitHub Action. You can find detailed steps for each repository in my guide about creating a CDK construct using projen and jsii on GitHub. Besides that, you don’t need to do anything. Just commit your changes and wait for the magic to happen!
Conclusion
I hope you were successful in migrating your existing CDK construct to projen
and jsii
. In my opinion it offers a really good way to manage your project and hide quite a few complicated steps. Also, shipping to various repositories works like a charm!
Are you running into any errors? Comment below and let me see if I can help you 😊