On a Sunday morning, as you walk towards the bakery, the aroma of freshly baked buns fills the air. You can't resist taking a bite of the hot bun fresh from the oven as soon as you get it.
Now, it’s most likely that you burn yourself or you are smart and let it cool down a bit.
Bun is so cool that I also got hyped. However, I questioned myself:
- How can I use it in my current or future projects?
- How can I deploy it?
- Do I have to rewrite a lot or even everything?
In this blog post, we will discover the usage of Bun by creating an AWS CDK template using Bun tooling.
It means how your computer interprets your script. Each programming language has its Syntax and grammar; you can run a program using their language1. For example, if you write a Python script, you run it with
python myscript.py. The machine uses Python as runtime to interpret it. The file extension allows humans to understand that this is a Python file or editors to do color highlighting, but it’s unnecessary for the machine.
The same applies to NodeJS and Bun. You can execute the script by running
node myscript.js and
More interesting is what Syntax Bun supports. - A bun of (pun intended ✊) including Typescript, JSX, and JSON2.
What if we want to deploy a function to any Cloud provider such as Cloudflare or AWS? None of them support these for now (28. September 2023).
Remember, we need to run
bun myscript.ts. Luckily, on AWS Lambda, we could create a custom runtime.
That means we don’t need to transpile the Typescript code to ESM or CJS. Currently, only Deno Deploy can run your Typescript function out of the box. However, in order to keep the code small, we still need some sort of bundling. Luckily, Bun is also a bundler 😉
A bundler is a tool that puts your code into a single file. When you develop a function, you may split your code into multiple files and use third-party packages. So, instead of shipping the whole
node_modules- folder or all the libraries, a bundler only uses the correct code.
Furthermore, Node-Server cannot understand Typescript, so we use a bundler to transpile and bundle.
As a cloud engineer, I am working a lot with AWS CDK, a tool for infrastructure on AWS. Usually, I develop my AWS Resources in SST (here are my thoughts on SST and not in Projen (here are my thoughts on Projen.
AWS CDK is an open-source software development framework developed by Amazon Web Services (AWS) that allows developers to define and provision cloud infrastructure resources using familiar programming languages.
Their CLI bootstraps an npm project. I used that to Bunyfied it.
On this attempt
bunx runs the fastest but is not really impressive.
Bun comes with its own testing suite, and it gives you nice hints in order to make this test pass 😇
And I have to say the
--watch mode is really fast.
vitest is also fast and reruns only failed tests, which makes it, in the end, faster (here when using Monorepo).
However, Mocking didn't work as expected. I attempted to spy on a function to manipulate a result but was unsuccessful. Their mocks provided were also unusable when trying to mock out the functions of packages. The documentation was not helpful either. As a result, I had to abandon
bun test and used
When I installed Lambda Powertools, Bun became significantly faster. It turns out that I had already installed some packages, but still, Bun was faster than pnpm.
I created a Monorepo because Bun supports Workspaces).
Bun has its own package for creating a Lambda Layer.
I created a
BunFunLayerStack to deploy a Lambda Layer. That layer is customizable and could be consumed by another account, or you could even make it public.
Then, I created a Construct
BunFun which creates a
Function using the Lambda Layer.
It tries to read Arn, resulting from the
BunFunLayerStack but can be overwritten when passing
props.bunLayer in case you bring your own Layer.
node it will be the target. But then you could use the
NodeJsFunction- Construct of CDK. However, when you need the Bun there is a
bunConfig- property that also opens up all the Bun configurations from their bundler API.
Generally, I put three examples in the
I put a couple of Lambdas in the
packages/functions to get started and I realized that the Lambdas using that runtime must always return a
new Response. Otherwise, the Lambda will not execute successfully. But that doesn't mean you cannot use it for handling SQS.
BunFunLayerStack can be deployed separately. In this repo, I put them into an
bun deploy:all to deploy the
BunOvenStack and run
bun deploy:only to deploy only the
bun deploy:only is also parameterized and could run another stack e.g.
STACK=BunFunLayerStack bun deploy:only.
In this blog post, I used Bun's tooling to create an AWS CDK project. It includes a Layer for deploying a Bun Runtime and a Construct for creating a BunFunction.
Why should we care? Well, Bun would eliminate the fact of either using CommonJS or EcmaScript Modules (ESM) because most of the developers (me included) simply don't care. With the Bun runtime, you would run your Typescript files without transpiling them. Furthermore, Bun is fast. This blog does not cover benchmarking the Lambdas with a Bun runtime as there are already Benchmarks for Bun’s performance3.
bun test was not usable, and I use
vitest instead. Moreover, the Lambda Runtime requires you always return
new Response when using the
bun target. This could be confusing when using Lambda for a different purpose then using an API Gateway.
With my Bunnyfied AWS CDK template, you could already start deploying Lambda functions using Bun Runtime, so give it a shoot 😉
To try it out, use the following command
bun create github.com/jolo-dev/bunnyfied-aws-cdk
P.S.: It's faster than the
npx cdk init app.
P.S.S: Feedback and Contributions are welcome!