Migrating a CDK Construct to projen and jsii
Tags: aws, awscdk, cdkconstruct, projen
Published: 2021-03-02 08:43:08

---
title: Migrating a CDK Construct to projen and jsii
published: true
date: 2021-03-01 09:00:00 UTC
tags: aws, awscdk, cdkconstruct, projen
canonical_url: https://www.sebastianhesse.de/2021/03/01/migrating-a-cdk-construct-to-projen-and-jsii/
---

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](https://github.com/seeebiii/projen-test). 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](https://github.com/projen/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](https://github.com/seeebiii/projen-test/blob/main/.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](https://github.com/aws/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](https://aws.amazon.com/blogs/opensource/generate-python-java-dotnet-software-libraries-from-typescript-source/) 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:

```shell
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](https://jestjs.io/) 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](https://eslint.org/) 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](https://www.matthewbonig.com/2020/10/04/converting-to-projen/) 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:

```shell
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`:

1. Make according changes in `.projenrc.js`.
2. Run `npx projen` and `projen` will synthesize the changes to all project files. 💡 Hint: create an alias like `pj` in your command line to avoid typing `npx projen` over and over again.
3. Never manually edit the generated files because `projen` will overwrite them the next time!

If you have used tools like `eslint` or [Dependabot](https://dependabot.com/) 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](https://cdk.dev/).

### 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](https://www.sebastianhesse.de/2021/01/16/5-ways-to-bundle-a-lambda-function-within-an-aws-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`:

```javascript
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](#release-settings), `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](https://github.com/seeebiii/projen-test#publishing-to-different-repositories). Besides that, you don’t need to do anything. Just commit your changes and wait for the magic to happen!

![Successful CDK construct release using projen and jsii.](https://www.sebastianhesse.de/wp-content/uploads/2021/02/successful-projen-action-run-1024x516.png)<figcaption>A successful release using projen and jsii. Example taken from <a href="https://github.com/seeebiii/projen-test" target="_blank">projen-test</a>.</figcaption>

## 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 😊

The post [Migrating a CDK Construct to projen and jsii](https://www.sebastianhesse.de/2021/03/01/migrating-a-cdk-construct-to-projen-and-jsii/) was first published on [Sebastian Hesse - Software Engineer](https://www.sebastianhesse.de).