
Serverless Framework meets the CDK 🚀
Setting the scene
Say your team is using the Serverless Framework for your current project, and you have the following basic bespoke requirements for your IaC:
- If the stage is production or staging, add a CloudWatch alarm to the lambda, however if it is QA or ephemeral environments (e.g. pr-123) then don’t. This may be because you want to reduce the costs in these environments, and you would get a lot of junk alerts during development that you don’t want.
You could take this further and further, for example:
- If the stage is QA or an ephemeral environment then share an ElasticSearch cluster with the index names generated using the stage as a prefix; however in production or staging create a separate ES cluster. You may do this in non-prod/non-staging due to the time it would take to create and delete the cluster each time for an ephemeral environment, as well as cost.
- In production or staging have 3 instances, however in QA or an ephemeral environment use 1 instance. Again, this could be to reduce costs, and your load testing is only ran in staging and production where you need the larger cluster for confidence.
Note: These are fictitious requirements just to show how creative you can get with this approach regardless of how bespoke your requirements are.
With the Serverless Framework and YML these bespoke requirements can be fairly cumbersome and difficult to achieve (even when using plugins created by the community), yet when using a framework such as the AWS CDK this can easily be achieved as you have the ability to use TypeScript for conditional programming and importing functions.
So how do we achieve this with the Serverless Framework?
One way of achieving this is to use JS or TS for your serverless config file rather than using YML (serverless.js
or serverless.ts
), which opens up the ability to use imported functions to essentially make the serverless framework 100% extensible. If you can do it in JavaScript or TypeScript then you can do it in the serverless framework and your IaC too! 💥
This is described further here in the Serverless Framework documentation as well as examples for both Node and TypeScript: https://www.serverless.com/framework/docs/providers/aws/guide/intro#services
The Framework also handles natively exporting JSON object from a Javascript file
serverless.js
or from a Typescript fileserverless.ts
at the root directory of the project. While the Framework is language-agnostic, projects written in Node.js will highly benefit from using the same language for the service definition file.
Most teams naturally reach straight for YML, as let's face it, it is much prettier than JSON, but less extensible in my opinion! 😍
My teams and I used this approach on a large scale enterprise serverless project two years ago and this method was very successful. This approach alongside Jest meant we could actually unit test our logic too (including snapshots of the CloudFormation outputs) for greater peace of mind around our IaC as it should be deterministic; and we also had reusable functions, types and interfaces within packages in our Lerna monorepo to utilise them across multiple serverless services.
This also allowed us to make the resources and config more moduler with a predefined folder strategy for our varying resources (this can be achieved also in YML by pulling in external files, however with TS/JS you can import directly and click through to the functions natively in your IDE which is a nicer developer experience).
OK, sounds good — show me an example!
When you use the templating feature from the Serverless framework CLI, choose the aws-nodejs-typscript template type it will generate the following default serverless.ts in the root folder for you with API Gateway and a ‘hello’ lambda function (call and autogenerated output below):
serverless create --template aws-nodejs-typescript
This allows us to then create and unit test a new function called configureAlarms for our specific requirement around alarms (above), based on the stage environment variable; which can then be imported into the serverless.ts file and used. This will essentially spread in the correct CloudFormation returned from the function into the Resources section. For example on line 33:
The following sudo code shows how the imported configureAlarms function might look in this example:
And running the serverless command with the stage environment variable you’re deploying (or you could use the dotenv feature in serverless for this too):
STAGE=prod sls deploy --stage=prod
Thats awesome, any other benefits?
With this approach there are also three other benefits:
- The configuration options around the serverless config has grown massively over the past few years, and is now very verbose. Through the use of Serverless + TypeScript you will have the explicit types for the config, allowing you to browse the configuration with your IDE intellisense. This is a major benefit over YML.
- If you have generic functions which could be shared and utilised across multiple serverless projects you can package and import them via NPM or through using a monorepo for greater reuse.
- You can type your stages (as I have done above and imported them) and pull in your stage value from a config file to ensure there are no typing errors in your IaC code, as well as ensuring the environment variable has been supplied (if not the error will prevent the serverless deploy). The config file can be as simple as the following below to make sure you don’t have to use
process.env.STAGE
everywhere in your code i.e. wrap it nicely in a config service which can be imported anywhere:
// the imported getStage function just returns the value of
// process.env.STAGE and throws an error if it is not supplied
const stage = getStage();export const config = {
stage: `${stage}`,
};
Wrapping up
Although this is a basic sudo code example of what you can achieve, hopefully this will show an approach which may fit your requirements when YML is too restrictive.
Lets connect on any of the following:
https://www.linkedin.com/in/lee-james-gilmore/
https://twitter.com/LeeJamesGilmore
If you found the articles inspiring or useful please feel free to support me with a virtual coffee https://www.buymeacoffee.com/leegilmore and either way lets connect and chat! ☕️
If you enjoyed the posts please follow my profile Lee James Gilmore for further posts/series, and don’t forget to connect and say Hi 👋
This article is sponsored by Sedai.io

About me
“Hi, I’m Lee, an AWS certified technical architect and polyglot software engineer based in the UK, working as a Technical Cloud Architect and Serverless Lead, having worked primarily in full-stack JavaScript on AWS for the past 5 years.
I consider myself a serverless evangelist with a love of all things AWS, innovation, software architecture and technology.”
** The information provided are my own personal views and I accept no responsibility on the use of the information.