DEV Community

Cover image for AWS Lambda Meets Bun through SST 🐰: Prime Time or Just Prime Hype? 🥵
Valentin BEGGI for Serverless By Theodo

Posted on

AWS Lambda Meets Bun through SST 🐰: Prime Time or Just Prime Hype? 🥵

TL;DR

⚡ Deploy Bun in AWS Lambda swiftly and efficiently with SST's streamlined process.
🐰 Dive into the integration of Bun with Lambda through SST and evaluate its readiness for your use-case.

1️⃣ Load the Bun Layer to your AWS Account

💡 Before you start, ensure you have an AWS account and that you're logged in via the AWS CLI.

To verify your login status, execute the following command:

aws sts get-caller-identity

If you are not logged in, run the command below:

aws configure

We'll be utilizing the official Bun layer for Lambda, provided by the Bun team 🐰.

Follow the instructions listed on the Bun Layer page to add the layer to your AWS account.

When executing bun publish-layer, ensure you choose the aarch64 architecture ⚡!

bun run publish-layer -- \
  --arch aarch64 \
  --region eu-west-1
Enter fullscreen mode Exit fullscreen mode

Afterward, navigate to your AWS console, access the Lambda service, and verify that the layer is available.
Make a note of its ARN; we'll be using it later. 🧠

AWS Lambda layer in the console

2️⃣ Deploy a new SST app 🔥

SST is a framework designed to streamline the deployment of Serverless applications on AWS. If you're curious about why we favor SST over the Serverless Framework, check out our previous article: Best Serverless Framework in 2023: A Data-Driven Showdown for AWS Projects

Proceed with the steps in SST's standalone get started section.

In essence, you'll execute:

npx create-sst@latest my-sst-app
Enter fullscreen mode Exit fullscreen mode

Install your dependencies and then deploy your app (we already made sure you are logged in via the AWS CLI 😉). It will run cdk bootstrap under the hood so you don't have to worry about it.

📝 For a quick test of Bun in Lambda, consider removing all resources in MyStack.ts except the lambda resource. We'll adjust it later.

Upon completion, your app should be deployed with a Node.js Lambda function. Next, we'll modify your stack resources to make the lambda run Bun!

3️⃣ Add the Bun Layer to your lambda, and execute bun 🐰

Let's incorporate some Bun code into our Lambda.

First, add this to your tsconfig.json

{
  "compilerOptions": {
    "types": ["bun-types"] // add Bun global
  }
}
Enter fullscreen mode Exit fullscreen mode

Then, draft a basic lambda handler leveraging the Bun.password API (this ensures Bun is operational!):

let hashedPassword = null;

export default {
  async fetch(request: Request): Promise<Response> {
    const { password, action } = (await request.json()).event as {
      password: string;
      action: "get" | "set";
    };

    switch (action) {
      case "set":
        hashedPassword = await Bun.password.hash(password);

        return new Response(
          JSON.stringify({
            statusCode: 200,
            body: { result: "Password has been set." },
          })
        );

      case "get":
        const isVerified = await Bun.password.verify(password, hashedPassword);

        return new Response(
          JSON.stringify({
            statusCode: 200,
            body: { result: isVerified },
          })
        );
    }
  },
};
Enter fullscreen mode Exit fullscreen mode

💡 In the above code, the password is set in Lambda's memory. The variable will be lost whenever a new instance of this lambda is created.

Now, it's time to deploy our modifications! 🚀

In your MyStack.ts file, add the following code:

new Function(stack, "my-bun-function", {
  // 👇 This is required to use custom runtimes
  runtime: Runtime.PROVIDED_AL2,
  handler: "lambda.fetch",
  // 👇 That's why we published bun layer with aarch64 architecture
  architecture: Architecture.ARM_64,
  code: Code.fromAsset("out"),
  memorySize: 1024,
  timeout: Duration.seconds(10),
  layers: [
    LayerVersion.fromLayerVersionArn(
      stack,
      "bunLayer",
      // 👇 Replace with your layer ARN
      YOUR_BUN_LAYER_ARN
    ),
  ],
});
Enter fullscreen mode Exit fullscreen mode

Lastly, in your package.json file, refresh the deploy command to:

    "deploy": "bun build --outdir=out packages/functions/src/PATH_TO_YOUR_HANDLER --target bun && sst deploy"
Enter fullscreen mode Exit fullscreen mode

💡 If you need to deploy several lambdas, a dedicated build step to minify bun code would be necessary!

Now, run your deploy command, and go check your lambda in the AWS console. You should be able to test it with an input event that matches the one we used in our code.

{
  "password": "my-password",
  "action": "set"
}
Enter fullscreen mode Exit fullscreen mode

To take it a step further, connect your Lambda to an API Gateway, or generate a function URL via the AWS console for testing!

4️⃣ Conclusion & Caveats 🥲

Using the custom Bun Layer comes at a cost: ~500ms cold start time. 🥶

After conducting tests on computationally intensive tasks ( calculating Fibonacci sequences), I observed performance to be twice as slow compared to the native Node.js runtime. 🐢

Personally, I believe Bun in Lambda isn't production-ready. We can only hope AWS introduces a native Bun runtime in the near future! 🤞

If you discovered a more efficient method to deploy Bun in Lambda or if your performance results differ from mine, please share your experiences in the comments! 🙏

Top comments (0)