---
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
```