AWS Lambda & Bun: A Perfect Match for Serverless Bliss
Durgaprasad Budhwani
Founder & Innovator at SiteLifter | Empowering Productivity with AI Assistants for LinkedIn, WhatsApp & Twitter | Driving User Engagement & Community Growth
Serverless computing has revolutionized the way we build and deploy applications, offering scalability and cost-efficiency like never before. AWS Lambda, Amazon's serverless compute service, has played a pivotal role in this paradigm shift. Lambda allows developers to run code in response to events without the need to manage servers.
However, Lambda's default runtime environment supports only a limited set of programming languages. If your favorite language isn't among them, you might find yourself facing a roadblock. That's where custom runtimes and extensions come into play. In this blog post, we'll explore how you can use a custom runtime layer to run Bun on AWS Lambda.
Title: Unleashing the Power of Bun with AWS Lambda Extensions
Introduction
Serverless computing has revolutionized the way we build and deploy applications, offering scalability and cost-efficiency like never before. AWS Lambda, Amazon's serverless compute service, has played a pivotal role in this paradigm shift. Lambda allows developers to run code in response to events without the need to manage servers.
However, Lambda's default runtime environment supports only a limited set of programming languages. If your favorite language isn't among them, you might find yourself facing a roadblock. That's where custom runtimes and extensions come into play. In this blog post, we'll explore how you can use a custom runtime layer to run Bun on AWS Lambda.
Bun:
Bun is a new JavaScript runtime built from scratch to serve the modern JavaScript ecosystem. It has three major design goals:
Bun is designed as a drop-in replacement for Node.js. It natively implements hundreds of Node.js and Web APIs, including fs, path, Buffer and more.
The goal of Bun is to run most of the world's server-side JavaScript and provide tools to improve performance, reduce complexity, and multiply developer productivity.
AWS Lambda Layer:
AWS Lambda Layers is a versatile feature that allows you to manage and reuse code, libraries, and dependencies across multiple Lambda functions. While I've covered the basics, here's a more in-depth exploration of Lambda Layers and how they can be used for runtime enhancements:
1. Code Isolation and Reusability:
Lambda Layers enable you to isolate your code and dependencies from your Lambda function's deployment package. This separation enhances code reusability, reduces duplication, and simplifies code maintenance.
2. Runtimes and Custom Runtimes:
Lambda Layers can contain custom runtime environments, which is a powerful capability. This allows you to run Lambda functions in languages and versions not natively supported by AWS Lambda. For instance, you can create a custom runtime layer for running operations written in Rust, Kotlin, or any language you choose.
3. Runtime Environment Customization:
You can use Lambda Layers to customize the runtime environment of your Lambda functions. For example, you can include environment variables, initialization code, or configurations specific to your application.
4. Shared Libraries and Dependencies:
Share common libraries and dependencies across multiple Lambda functions within an application. This reduces the size of individual deployment packages and simplifies updates when there are changes or security patches to libraries.
Running AWS Lambda Functions with Bun: A Step-by-Step Guide:
Step 1: Prerequisites
Step 2: Deploy Bun Lambda Layer:
Bun team has provided the official documentation for the bun lambda. Please refer the link (https://github.com/oven-sh/bun/tree/main/packages/bun-lambda)
Clone this repository and run the publish-layer script to get started. Note: the publish-layer hand also builds the layer.
git clone [email protected]:oven-sh/bun.git
cd bun/packages/bun-lambda
bun install
bun run publish-layer
bun run publish-layer has the following arguments:
--layer: The layer name. The default value is bun
--region: The region name, or "*" for all regions.
--public: If the layer should be public. The default value is false.
--arch: The architecture, either: "x64" or "aarch64". For lambda arm64, the architecture will be aarch64 and for x86_64 based lambda, the architecture will be x64
The full example will be:
bun run publish-layer -- \
--arch aarch64 \
--release latest \
--region us-east-1
This will be deploy arm64 lambda layer and after the deployment, you will get published lambda layer ARN. This ARN will be required for the Lambda Deployment for Lambda Function deployment.
Step 3: Create Lambda Function:
mkdir app && cd app
bun init -y
This will create a default Bun application.
export default {
async fetch(request: Request): Promise<Response> {
// ...
return new Response("Hello from Lambda! via Bun Lambda Layer", {
status: 200,
headers: {
"Content-Type": "text/plain",
},
});
},
};
This code exports an object with a single asynchronous function, fetch, typically used in the context of an AWS Lambda function. Let's break down what this code does:
To build the code, run the following command:
bun build --minify --splitting --outdir=dist ./index.ts
The command is used to build a TypeScript file (index.ts) using "bun" with specific options and output configuration. Here's a breakdown of the command:
Step 4: Deployment using AWS CDK:
To get started with the AWS Cloud Development Kit (CDK) for deployment, follow these short notes:
mkdir deploy && cd deploy
npm install -g aws-cdk
cdk init app --language=typescript
This will initialized the CDK project. Navigate to lib/deploy-stack.ts file and update the following code snippet:Imports:
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import { Runtime, Function, Code, LayerVersion, FunctionUrlAuthType, Architecture } from 'aws-cdk-lib/aws-lambda';
import * as path from 'path';
import { CfnOutput } from 'aws-cdk-lib';
export class DeployStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
// ... rest of the code
}
}
The DeployStack class extends the cdk.Stack class, indicating that it represents an AWS CloudFormation stack.
const lambdaLayer = LayerVersion.fromLayerVersionArn(this, 'BunLayer', 'arn:aws:lambda:us-east-1:XXXXXX:layer:bun:1');
This section defines a Lambda Layer named BunLayer by creating an instance of LayerVersion and specifying its ARN. The ARN points to an existing Lambda Layer.
4. Lambda Function Configuration:
const lambdaFunction = new Function(this, 'BunFunction', {
runtime: Runtime.PROVIDED_AL2,
code: Code.fromAsset(path.join(__dirname, '../../app/dist')),
handler: 'index.fetch',
layers: [lambdaLayer],
functionName: 'bun',
architecture: Architecture.ARM_64,
});
This section configures the Lambda function named BunFunction.It uses the Runtime.PROVIDED_AL2, which suggests that the runtime is provided by the layer.The function's code is sourced from the specified directory using Code.fromAsset.The handler indicates that the function is located in the index file and the fetch function is the entry point.The Lambda function is associated with the lambdaLayer.It is given the name bun.The architecture is set to Architecture.ARM_64, which indicates the architecture of the Lambda function.
const lambdaUrl = lambdaFunction.addFunctionUrl({
authType: FunctionUrlAuthType.NONE,
});
This section configures the URL for the Lambda function.The authType is set to FunctionUrlAuthType.NONE, indicating that no authentication is required to access the function URL.
new CfnOutput(this, 'FunctionUrl', { value: lambdaUrl.url });
This code defines a CloudFormation output that displays the URL of the Lambda function. The output is named 'FunctionUrl'.
Full Code:
import * as cdk from 'aws-cdk-lib';
import {Construct} from 'constructs';
import {Runtime, Function, Code, LayerVersion, FunctionUrlAuthType, Architecture} from "aws-cdk-lib/aws-lambda";
import * as path from "path";
import {CfnOutput} from "aws-cdk-lib";
// import * as sqs from 'aws-cdk-lib/aws-sqs';
export class DeployStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
// The code that defines your stack goes here
const lambdaLayer = LayerVersion.fromLayerVersionArn(this, 'BunLayer', 'arn:aws:lambda:us-east-1:XXXXXX:layer:bun:1')
const lambdaFunction = new Function(this, 'BunFunction', {
runtime: Runtime.PROVIDED_AL2,
code: Code.fromAsset(path.join(__dirname, '../../app/dist')),
handler: 'index.fetch', // index is the name of the file and fetch is the name of the function
layers: [lambdaLayer],
functionName: 'bun',
architecture: Architecture.ARM_64, // ARM_64 is the architecture of the lambda function and this will changed based on the bun image architecture
});
const lambdaUrl = lambdaFunction.addFunctionUrl({
authType: FunctionUrlAuthType.NONE,
});
new CfnOutput(this, 'FunctionUrl ', { value: lambdaUrl.url });
}
}
cdk synth && cdk deploy
This will deploy the stack and at the end you will get the function URL
When you open the URL in the browser, you will see the message:
Hello from Lambda! via Bun Lambda Layer
Conclusion
In conclusion, serverless computing has ushered in a transformative era in application development, offering unprecedented scalability and cost-efficiency. AWS Lambda, Amazon's serverless compute service, has been at the forefront of this shift by enabling developers to execute code in response to events without the need to manage servers.
However, one limitation of AWS Lambda's default runtime environment is its support for only a select set of programming languages. If your preferred language is not on the list, it can be a roadblock to your development efforts. This is where custom runtimes and extensions come into play, providing a solution to this challenge.
In this post, we've explored how you can harness the power of Bun, a modern JavaScript runtime, within AWS Lambda using custom runtime layers. Bun is designed for speed, elegant APIs, and a cohesive developer experience. It serves as a drop-in replacement for Node.js, implementing a wide range of Node.js and Web APIs.
We've also delved into AWS Lambda Layers, a versatile feature for managing and reusing code, libraries, and dependencies across multiple Lambda functions. Layers offer several advantages, including code isolation, runtime customization, and shared libraries.
To put this into practice, we've outlined a step-by-step guide for running AWS Lambda functions with Bun:
By following these steps, you can unlock the full potential of Bun within AWS Lambda, leveraging custom runtimes and layers to expand your serverless development capabilities. This approach allows you to use your preferred language and runtime environment while benefiting from the scalability and serverless advantages provided by AWS Lambda. Happy serverless coding!
Source Code:
You can find the source code in the provided repository: aws-lambda-bun-layer-example.
You can follow me on LinkedIn to get the latest updates on Serverless and AI.
#Serverless #AWSLambda #Bun #ServerlessDevelopment #CustomRuntimes #LambdaLayers
Engineer, Maker, Entrepreneur
1 年But can the CDK app portion be done with Bun instead of node?
Software Engineer (AWS) at Tellimer
1 年How does this improve on node specifically when using this with lambda, are there cold start improvements, request response time improvements, cost optimisations?