--- title: Lambda description: Deploy serverless functions using AWS Lambda and API Gateway --- import { Aside } from '@astrojs/starlight/components'; import LambdaArchitecture from '@/components/docs/patterns/LambdaArchitecture.astro'; import LambdaZipPipeline from '@/components/docs/patterns/LambdaZipPipeline.astro'; import LambdaContainerPipeline from '@/components/docs/patterns/LambdaContainerPipeline.astro'; Deploy serverless APIs and backend functions on [AWS Lambda](https://aws.amazon.com/lambda/) with [API Gateway](https://aws.amazon.com/api-gateway/) as the public HTTP endpoint. Scales to zero when idle — pay only for what you use. ## Supported Frameworks - [Hono](https://hono.dev/) - [NestJS](https://nestjs.com/) - [Fastify](https://www.fastify.io/) - [Koa](https://koajs.com/) - [AdonisJS](https://adonisjs.com/) - [Feathers](https://feathersjs.com/) - Any framework that exports a Lambda handler ## AWS Resources | Resource | Purpose | | --- | --- | | [Lambda Function](https://aws.amazon.com/lambda/) | Runs your server code | | [API Gateway HTTP API](https://aws.amazon.com/api-gateway/) | Public HTTP endpoint, routes all traffic to Lambda | | [CloudWatch Logs](https://aws.amazon.com/cloudwatch/) | Function logs, retained for 1 month | | [ACM Certificate](https://aws.amazon.com/certificate-manager/) | SSL for custom domain (optional) | | [Route53](https://aws.amazon.com/route53/) | DNS A + AAAA records (optional) | ## Serverless API Architecture ## Quick Start ### Installation ```bash bun add -D @thunder-so/thunder ``` ### Configuration ```ts title="stack/prod.ts" import { Cdk, Lambda, type LambdaProps } from '@thunder-so/thunder'; const config: LambdaProps = { env: { account: 'YOUR_ACCOUNT_ID', region: 'us-east-1', }, application: 'myapp', service: 'api', environment: 'prod', rootDir: '.', functionProps: { runtime: Cdk.aws_lambda.Runtime.NODEJS_22_X, architecture: Cdk.aws_lambda.Architecture.ARM_64, codeDir: 'dist', handler: 'index.handler', memorySize: 512, timeout: 10, }, }; new Lambda( new Cdk.App(), `${config.application}-${config.service}-${config.environment}-stack`, config ); ``` ### Deploy ```bash bun run build npx cdk deploy --app "bunx tsx stack/prod.ts" --profile default ``` CDK outputs the API Gateway URL: ``` Outputs: myapp-api-prod-stack.ApiGatewayUrl = https://abc123.execute-api.us-east-1.amazonaws.com ``` ## Custom Domain Connect your API to a custom domain. The certificate must be issued in the **same region as your Lambda function** — unlike Static, Lambda uses a regional (not global) certificate. ```ts title="stack/prod.ts" const config: LambdaProps = { // ... domain: 'api.example.com', hostedZoneId: 'Z1D633PJN98FT9', regionalCertificateArn: 'arn:aws:acm:us-east-1:123456789012:certificate/abc-123', }; ``` ## Advanced Configuration ### Performance and Concurrency Fine-tune your function's performance with memory, timeout, and concurrency settings. Memory also controls proportional CPU allocation. ```ts title="stack/prod.ts" const config: LambdaProps = { // ... functionProps: { runtime: Cdk.aws_lambda.Runtime.NODEJS_22_X, architecture: Cdk.aws_lambda.Architecture.ARM_64, memorySize: 1792, // more memory = more CPU timeout: 10, tracing: true, // enable AWS X-Ray keepWarm: true, // ping every 5 min to prevent cold starts reservedConcurrency: 10, // hard cap on simultaneous executions provisionedConcurrency: 2, // pre-warmed instances, eliminates cold starts url: true, // also expose a direct Lambda Function URL }, }; ``` ### Environment Variables and Secrets ```ts title="stack/prod.ts" const config: LambdaProps = { // ... functionProps: { variables: [ { NODE_ENV: 'production' }, { API_URL: 'https://api.example.com' }, ], secrets: [ { key: 'DATABASE_URL', resource: 'arn:aws:secretsmanager:us-east-1:123456789012:secret:/myapp/DATABASE_URL-abc123', }, ], }, }; ``` Thunder automatically grants the Lambda execution role `secretsmanager:GetSecretValue` on each referenced secret. ## Container Deployments Deploy Lambda functions as container images to use custom runtimes, package large dependencies, or exceed the 250 MB zip limit. Container images support up to 10 GB. ### Node.js Container ```dockerfile title="Dockerfile" FROM public.ecr.aws/lambda/nodejs:22 AS builder WORKDIR ${LAMBDA_TASK_ROOT} COPY . . RUN npm ci RUN npm run build FROM public.ecr.aws/lambda/nodejs:22 WORKDIR ${LAMBDA_TASK_ROOT} COPY --from=builder /var/task/dist/* ./ COPY --from=builder /var/task/node_modules ./node_modules CMD ["index.handler"] ``` ```ts title="stack/prod.ts" const config: LambdaProps = { // ... functionProps: { dockerFile: 'Dockerfile', memorySize: 1792, keepWarm: true, }, }; ``` ### Bun Runtime Container [Bun](https://bun.sh/) is not a managed Lambda runtime, so it runs as a container. The bootstrap binary handles the Lambda runtime protocol and forwards requests to your Bun fetch handler. ```dockerfile title="Dockerfile.bun" # Stage 1: Build the Bun Lambda bootstrap FROM oven/bun:latest AS bun WORKDIR /tmp RUN apt-get update && apt-get install -y curl RUN curl -fsSL https://raw.githubusercontent.com/oven-sh/bun/main/packages/bun-lambda/runtime.ts -o runtime.ts RUN bun install aws4fetch RUN bun build --compile runtime.ts --outfile bootstrap # Stage 2: Build your app FROM oven/bun:latest AS builder WORKDIR /tmp COPY . . RUN bun install RUN bun run build # Stage 3: Runtime image FROM public.ecr.aws/lambda/provided:al2023 WORKDIR ${LAMBDA_TASK_ROOT} COPY --from=bun /tmp/bootstrap ${LAMBDA_RUNTIME_DIR} COPY --from=builder /tmp/dist/ ./ COPY --from=builder /tmp/node_modules ./node_modules CMD ["lambda-bun.fetch"] ``` ```ts title="stack/prod.ts" const config: LambdaProps = { // ... functionProps: { dockerFile: 'Dockerfile.bun', memorySize: 512, keepWarm: true, }, }; ``` ## CI/CD Pipeline ### Zip Deployment Pipeline ```ts title="stack/prod.ts" const config: LambdaProps = { // ... accessTokenSecretArn: 'arn:aws:secretsmanager:us-east-1:123456789012:secret:github-token-XXXXXX', sourceProps: { owner: 'your-username', repo: 'your-repo', branchOrRef: 'main', }, buildProps: { runtime: 'nodejs', runtime_version: '22', installcmd: 'bun install', buildcmd: 'bun run build', outputDir: 'dist', }, }; ``` ### Container Deployment Pipeline ```ts title="stack/prod.ts" const config: LambdaProps = { // ... accessTokenSecretArn: 'arn:aws:secretsmanager:us-east-1:123456789012:secret:github-token-XXXXXX', sourceProps: { owner: 'your-username', repo: 'your-repo', branchOrRef: 'main', }, functionProps: { dockerFile: 'Dockerfile', }, buildProps: { installcmd: 'bun install', buildcmd: 'bun run build', }, }; ``` ## Stack Outputs | Output | Description | | --- | --- | | `ApiGatewayUrl` | API Gateway endpoint URL | | `LambdaFunction` | Lambda function name | | `LambdaFunctionUrl` | Direct Lambda URL (only if `url: true`) | | `Route53Domain` | Custom domain URL (only if `domain` is configured) | ## Destroy ```bash npx cdk destroy --app "bunx tsx stack/prod.ts" --profile default ```